C++ 如何将互斥体正确用作线程中memberfunction的参数?

C++ 如何将互斥体正确用作线程中memberfunction的参数?,c++,multithreading,c++17,mutex,C++,Multithreading,C++17,Mutex,我的问题是我不知道如何正确使用互斥。我从理论上理解它是如何工作的,但我不知道为什么它在我的代码中不起作用。我想如果我在变量上使用互斥锁,它将被阻止,直到解锁为止。尽管如此,我似乎仍然有一场数据竞赛 我试图定义一个类互斥体和一个通过引用传递的主互斥体。不知怎么的,这些都不管用 class test { public: void dosmth(std::mutex &a); int getT(){return t;}; private: int t = 0; };

我的问题是我不知道如何正确使用互斥。我从理论上理解它是如何工作的,但我不知道为什么它在我的代码中不起作用。我想如果我在变量上使用互斥锁,它将被阻止,直到解锁为止。尽管如此,我似乎仍然有一场数据竞赛

我试图定义一个类互斥体和一个通过引用传递的主互斥体。不知怎么的,这些都不管用


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;
        }
    }
}


课堂测试{
公众:
void dosmth(std::mutex&a);
int getT(){return t;};
私人:
int t=0;
};
无效测试::dosmth(标准::互斥和a){
对于(;;){
a、 锁();
t++;
如果(t==1000){
t=0;
}
a、 解锁();
}
}
int main(){
测试te;
互斥帮助;
std::线程t(&test::dosmth,std::addressof(te),std::ref(help));
对于(;;){

对于(int i=0;i只有当所述互斥用于调节对所有代码的输入(其中给定对象将被并发访问)时,互斥才能保证互斥。在您的情况下,您让第二个线程在主线程读取同一对象的值时修改对象的值
te.t
。但是,只有一个线程,正在使用互斥锁来保护对
te.t
的访问。对象
te.t
不是原子的。因此,存在数据竞争,因此存在未定义的行为

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

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

对于(int i=0;i只有当所述互斥用于调节对所有代码的输入(其中给定对象将被并发访问)时,互斥才能保证互斥。在您的情况下,您让第二个线程在主线程读取同一对象的值时修改对象的值
te.t
。但是,只有一个线程,正在使用互斥锁来保护对
te.t
的访问。对象
te.t
不是原子的。因此,存在数据竞争,因此存在未定义的行为

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

    for(;;){
        help.lock();
        for (int i = 0; i <te.getT() ; ++i) {
            std::cout<<te.getT()<<std::endl;
        }
        help.unlock();
    }
(;;)的
{
help.lock();
对于(int i=0;i
我想如果我在变量上使用互斥锁

您不在变量上使用互斥体。锁定互斥体可防止其他线程同时锁定同一互斥体,但不会阻止其他线程访问任何特定变量

如果您想使用互斥锁来保护一个变量(或者更典型地说,多个变量)不被多个线程同时访问,那么您需要确保在没有先锁定互斥锁的情况下,不会编写任何访问变量的代码

我想如果我在变量上使用互斥锁

您不在变量上使用互斥体。锁定互斥体可防止其他线程同时锁定同一互斥体,但不会阻止其他线程访问任何特定变量


如果要使用互斥来保护一个变量(或者更典型地说,多个变量)如果同时被多个线程访问,那么就由您来确保在没有锁定互斥锁的情况下不会编写任何访问变量的代码。

正如Michael提到的,您应该同步读写器以避免未定义的行为。common模式是使
互斥锁
成为对象的成员(
te
),每次进入成员函数(修改对象的内部状态)时锁定和解锁(首选
lock\u 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++;
    }
};
class-Foo{
std::mutex m;//读写器在同一个互斥体上同步
int数据到同步;
公众:
int read(){
锁_gaurdlg(m);//RAII锁
将数据返回到同步;
//退出时自动释放
}
无效写入(){
洛克高德lg(m);
数据同步++;
}
};

正如Michael提到的,您应该同步读写器以避免未定义的行为。与将
互斥体作为参数传递不同,一种常见的模式是使
互斥体成为对象的成员(
te
),每次锁定和解锁(首选
lock\u 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++;
    }
};
class-Foo{
std::mutex m;//读写器在同一个互斥体上同步
int数据到同步;
公众:
int read(){
锁_gaurdlg(m);//RAII锁
将数据返回到同步;
//退出时自动释放
}
无效写入(){
洛克高德lg(m);
数据同步++;
}
};

我不明白这个程序应该做什么?你想同步访问什么?@PeterT nothing我写它只是为了更好地理解互斥和如何避免数据竞争我不明白这个程序应该做什么?你想同步访问什么?@PeterT nothing我写它只是为了更好地理解mutex和如何避免数据争用是的。我认为
锁紧保护
已经“使用”了当描述符被调用时。那么for循环中的reption也是这样吗?我的意思是它在循环中是如何工作的?@MaestroD
lock
是循环块内类型为
std::lock\u guard
的局部变量。每次控制流遇到它的定义时,它都会被构造,每次控制流出现时,它都会被销毁ow在构造后退出块。换句话说:它将在循环的每次迭代开始时构造,并在循环的每次迭代结束时销毁…是的,它可以工作。我认为调用描述符时,
lock\u guard
是“使用”的。那么for循环中的reption也是这样吗,我的意思是它是如何工作的