мьютекс, используемый в функции, определенной внутри класса, похоже, не работает, когда эта функция вызывается в потоке в основном

      #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было передано по ссылке.

Другие вопросы по тегам