如何正确使用互斥量作为线程中成员函数的参数?

How to use mutex correctly as parameter for a memberfunction in a thread?

我的问题是我不知道如何正确使用互斥锁。我理解它在理论上是如何工作的,但我不知道为什么它在我的 code.I 思想中不起作用,如果我在 var 上使用互斥锁,它将被阻止,直到它被解锁。尽管如此,我似乎仍然存在数据竞争。

我试图定义一个 class 互斥锁和一个通过引用传递的 main 互斥锁。不知何故这一切都不起作用。


class test {
public:
    void dosmth(std::mutex &a);
    int getT(){return t;};

private:
    int t = 0;
};


void test::dosmth(std::mutex &a) {
    for(;;){
        a.lock();
        t++;
        if(t==1000){
            t=0;
        }
        a.unlock();
    }
}

int main() {
    test te;
    std::mutex help;
    std::thread t(&test::dosmth, std::addressof(te), std::ref(help));
    for(;;){
        for (int i = 0; i <te.getT() ; ++i) {
            std::cout<<te.getT()<<std::endl;
        }
    }
}

结果应该是我得到了一些输出,所以我现在可以使用了。

如果一个互斥量用于调节进入 all critical sections of code where a given object would be accessed concurrently. In your case, you have your second thread modify the value of the object te.t while your main thread is reading the value of the same object. Only one thread, however, is using a mutex to protect the access to te.t. The object te.t is not atomic. Therefore, you have a data race and, thus, undefined behavior [intro.races]/21.

,则该互斥量只能保证互斥

您还必须在 main 的 for(;;) 循环中锁定和解锁互斥体,例如:

    for(;;){
        help.lock();
        for (int i = 0; i <te.getT() ; ++i) {
            std::cout<<te.getT()<<std::endl;
        }
        help.unlock();
    }

或更好,使用 std::lock_guard:

    for(;;){
        std::lock_guard lock(help);
        for (int i = 0; i <te.getT() ; ++i) {
            std::cout<<te.getT()<<std::endl;
        }
    }

I thought if I use a mutex on a var...

您不使用互斥体 "on a var." 锁定互斥体可以防止其他线程同时锁定同一个互斥体,但它 不会 停止其他线程访问任何特定变量。

如果您想使用互斥锁来保护一个变量(或更典型地,多个变量)不被多个线程同时访问,那么由您决定 以确保您不会编写 任何 代码来访问变量而不先锁定互斥体。

正如 Michael 提到的,您应该同步 reader 和 writer 以避免未定义的行为。一种常见的模式是使 mutex 成为对象 (te) 的成员,而不是将 mutex 作为参数传递,每次都锁定和解锁(更喜欢 lock_gaurd而不是手动锁定和解锁)你输入一个成员函数(修改对象的内部状态)。这是一些伪代码:

class Foo{
    std::mutex m; // reader and writer are sync'ed on the same mutex
    int data_to_sync;
public:
    int read(){
        lock_gaurd<mutex> lg(m); //RAII lock
        return data_to_sync;
        //automagically released upon exit
    }
    void write(){
        lock_gaurd<mutex> lg(m);
        data_to_sync++;
    }
};