мьютекс, используемый в функции, определенной внутри класса, похоже, не работает, когда эта функция вызывается в потоке в основном
#include <thread>
#include <iostream>
#include <mutex>
class ThreadLessons {
private:
std::mutex _threading_mutex_in_class;
public:
ThreadLessons() {}
ThreadLessons(const ThreadLessons &tl) {}
ThreadLessons operator=(const ThreadLessons &tl) {return *this;}
void func(std::string s) {
std::unique_lock lg(_threading_mutex_in_class);
std::cout << std::endl;
for(int i{0}; i<10; i++) {
std::cout << s << std::endl;
}
}
};
std::mutex _threading_mutex;
void func(std::string s) {
std::unique_lock lg(_threading_mutex);
std::cout << std::endl;
for(int i{0}; i<10; i++) {
std::cout << s << std::endl;
}
}
int main()
{
std::cout << "Starting threading of function from another class in same file" << std::endl;
ThreadLessons t;
std::thread t1(&ThreadLessons::func, t, "Number 1");
std::thread t2(&ThreadLessons::func, t, "Number 2");
std::thread t3(&ThreadLessons::func, t, "Number 3");
t1.join();
t2.join();
t3.join();
std::cout << "Starting threading of function from main" << std::endl;
std::thread t4(func, "Number 4");
std::thread t5(func, "Number 5");
std::thread t6(func, "Number 6");
t4.join();
t5.join();
t6.join();
return 0;
}
Выход:
Starting threading of function from another class in same file
Number 1
Number 1
Number 1
Number 2
Number 2
Number 2
Number 3
Number 3
Number 1Number 2
Number 2
Number 3
Number 3Number 1
Number 2
Number 1Number 3Number 2
Number 2
Number 3
Number 3
Number 1
Number 1
Number 2
Number 1Number 3
Number 2
Number 1
Number 3
Number 3
Starting threading of function from main
Number 4
Number 4
Number 4
Number 4
Number 4
Number 4
Number 4
Number 4
Number 4
Number 4
Number 5
Number 5
Number 5
Number 5
Number 5
Number 5
Number 5
Number 5
Number 5
Number 5
Number 6
Number 6
Number 6
Number 6
Number 6
Number 6
Number 6
Number 6
Number 6
Number 6
Когда я вызываю функцию func из класса ThreadLessons, как видно из выходных данных, вывод № 1, № 2 и № 3 в std::cout не является детерминированным, как это должно быть при использовании мьютекса, для которого была получена блокировка. Обратите внимание, как номер 4, номер 5 и номер 6 являются детерминированными и последовательными.
Почему это не работает для мьютекса, определенного в функции внутри класса?
Пытался использовать std::cout в качестве общего ресурса и ожидал, что он будет использоваться как один при использовании внутри функции класса, которая блокирует мьютекс.
2 ответа
std::thread t1(&ThreadLessons::func, t, "Number 1");
std::thread t2(&ThreadLessons::func, t, "Number 2");
std::thread t3(&ThreadLessons::func, t, "Number 3");
В C++, когда вы что-то передаете функции, объект передается по значению . Фактически это означает, что создается копия объекта.
Здесь в конечном итоге происходит создание трех копий исходного объекта. Каждый вызов конструктора копируетt
, и каждый поток имеет свой собственный объект и свой собственный мьютекс.
Вам пришлось переопределить конструктор копирования, прежде чем он мог скомпилироваться, так какstd::mutex
не копируется. Это должна была быть большая, красная, гудящая подсказка: здесь делают копии.
Вместо,std::thread
имеет полезную перегрузку, которая вместо этого принимает указатель на объект:
std::thread t1(&ThreadLessons::func, &t, "Number 1");
std::thread t2(&ThreadLessons::func, &t, "Number 2");
std::thread t3(&ThreadLessons::func, &t, "Number 3");
Когда вы переходите к конструктору потока, создается копия. И у каждого экземпляра класса есть свой мьютекс. Мьютекс, который используется только одним потоком, довольно бесполезен.
С функцией free каждый вызов функции использует один и тот же мьютекс.
Чтобы передать объект по ссылке, вы можете использоватьstd::ref
:
std::thread t1(&ThreadLessons::func,std::ref(t), "Number 1");
На самом деле все еще делается копия, но копияstd::reference_wrapper
, который обертывает и действует как ссылка. Фактически это как быt
было передано по ссылке.