C++ 何时使用互斥

C++ 何时使用互斥,c++,mutex,C++,Mutex,事情是这样的:有一个float数组float bucket[5]和两个线程,比如thread1和thread2 Thread1负责将存储桶装满,为存储桶中的每个元素分配一个随机数。当铲斗加满油箱时,thread2将访问铲斗,并读取其元件 我是这样做的: float bucket[5]; pthread_mutex_t mu = PTHREAD_MUTEX_INITIALIZER; pthread_t thread1, thread2; void* thread_1_proc(void*);

事情是这样的:有一个float数组
float bucket[5]
和两个线程,比如thread1和thread2

Thread1负责将
存储桶装满,为
存储桶中的每个元素分配一个随机数。当铲斗加满油箱时,thread2将访问
铲斗
,并读取其元件

我是这样做的:

float bucket[5];
pthread_mutex_t mu = PTHREAD_MUTEX_INITIALIZER;
pthread_t thread1, thread2;

void* thread_1_proc(void*);  //thread1's startup routine, tank up the bucket 
void* thread_2_proc(void*);  //thread2's startup routine, read the bucket 

int main()
{
    pthread_create(&thread1, NULL, thread_1_proc, NULL);
    pthread_create(&thread2, NULL, thread_2_proc, NULL);
    pthread_join(thread1);
    pthread_join(thread2);
}
下面是我对thread_x_proc的实现:

void* thread_1_proc(void*)
{
    while(1) { //make it work forever
        pthread_mutex_lock(&mu);  //lock the mutex, right?

        cout << "tanking\n";
        for(int i=0; i<5; i++)
            bucket[i] = rand();  //actually, rand() returns int, doesn't matter

        pthread_mutex_unlock(&mu); //bucket tanked, unlock the mutex, right?

        //sleep(1); /* this line is commented */
    }
}

void* thread_2_proc(void*)
{
    while(1) { 
        pthread_mutex_lock(&mu);

        cout << "reading\n";
        for(int i=0; i<5; i++)
            cout << bucket[i] << " ";  //read each element in the bucket

        pthread_mutex_unlock(&mu); //reading done, unlock the mutex, right?

        //sleep(1); /* this line is commented */
    }
}
但是如果我取消注释
睡眠(1)
在每个thread_x_proc函数中,输出是正确的,
tanking
reading
如下所示:

...
tanking
reading
1.80429e+09 8.46931e+08 1.68169e+09 1.71464e+09 1.95775e+09 4.24238e+08 7.19885e+08 
tanking
reading
1.64976e+09 5.96517e+08 1.18964e+09 1.0252e+09 1.35049e+09 7.83369e+08 1.10252e+09 
tanking
reading
2.0449e+09 1.96751e+09 1.36518e+09 1.54038e+09 3.04089e+08 1.30346e+09 3.50052e+07
...

为什么??使用互斥锁时是否应使用
sleep()

如果有两个函数应按顺序执行,即F1应在F2启动前完成,则不应使用两个线程。F1返回后,在与F1相同的线程上运行F2


如果没有线程,您也不需要互斥锁。

如果有两个函数应该顺序执行,即F1应该在F2启动之前完成,那么您不应该使用两个线程。F1返回后,在与F1相同的线程上运行F2


如果没有线程,您也不需要互斥锁。

这不是真正的问题

睡眠只允许“另一个”线程访问互斥锁(碰巧,它正在等待锁,所以它可能会有互斥锁),但无法确保第一个线程不会重新锁定互斥锁,而让另一个线程访问它

互斥用于保护数据,因此两个线程不会: a) 同时写 b) 一个人在写,另一个人在读


这并不是为了让线程按特定顺序工作(如果您想要该功能,请放弃线程方法,或者使用标志来指示“水箱”已满)。

这并不是真正的问题

睡眠只允许“另一个”线程访问互斥锁(碰巧,它正在等待锁,所以它可能会有互斥锁),但无法确保第一个线程不会重新锁定互斥锁,而让另一个线程访问它

互斥用于保护数据,因此两个线程不会: a) 同时写 b) 一个人在写,另一个人在读


它不是为了让线程按特定的顺序工作(如果您想要该功能,请放弃线程方法或使用标志来指示“水箱”已满)。

没有隐含的线程运行顺序。这意味着您不应期待任何订单。更重要的是,它有可能得到线程运行一遍又一遍,而不让其他运行。这是特定于实现的,应假定为随机的

您介绍的案例更适合于添加了每个元素的“post”信号量

然而,如果它总是像:

  • 写5个元素
  • 阅读5个元素
您应该有两个互斥锁:

  • 在消费者完成之前阻止生产者的人
  • 一种在生产者完成之前阻止消费者的方法
所以代码应该是这样的:

Producer:
    while(true){
        lock( &write_mutex )
        [insert data]
        unlock( &read_mutex )
    }

Consumer:
    while(true){
        lock( &read_mutex )
        [insert data]
        unlock( &write_mutex )
    }
最初应解锁
write_mutex
,并锁定
read_mutex

正如我所说,对于信号量或条件变量,您的代码似乎是一个更好的例子。
互斥锁并不适用于这种情况(这并不意味着你不能使用它们,它只是意味着有更多方便的工具来解决这个问题)。

没有隐含的线程运行顺序。这意味着您不应期待任何订单。更重要的是,它有可能得到线程运行一遍又一遍,而不让其他运行。这是特定于实现的,应假定为随机的

您介绍的案例更适合于添加了每个元素的“post”信号量

然而,如果它总是像:

  • 写5个元素
  • 阅读5个元素
您应该有两个互斥锁:

  • 在消费者完成之前阻止生产者的人
  • 一种在生产者完成之前阻止消费者的方法
所以代码应该是这样的:

Producer:
    while(true){
        lock( &write_mutex )
        [insert data]
        unlock( &read_mutex )
    }

Consumer:
    while(true){
        lock( &read_mutex )
        [insert data]
        unlock( &write_mutex )
    }
最初应解锁
write_mutex
,并锁定
read_mutex

正如我所说,对于信号量或条件变量,您的代码似乎是一个更好的例子。
互斥锁并不适用于这种情况(这并不意味着你不能使用互斥锁,它只是意味着有更多方便的工具来解决这个问题)。

你没有权利假设,仅仅因为你希望你的线程按特定的顺序运行,实现就会找出你想要的,并实际按这个顺序运行它们

为什么thread2不能在thread1之前运行?为什么每个线程不能在另一个线程有机会运行到获取互斥锁的行之前完成它的循环几次呢


如果希望执行以可预测的方式在两个线程之间切换,则需要使用信号量、条件变量或其他机制在两个线程之间传递消息<代码>睡眠
在这种情况下似乎会按照您想要的顺序进行,但即使有了睡眠,您也没有做足够的工作来保证它们会交替进行。我不知道为什么
sleep
会对首先运行哪个线程产生影响——这在多次运行中是一致的吗?

您无权假设,仅仅因为您希望线程以特定的顺序运行,实现就会找出您想要的,并实际按该顺序运行它们

为什么thread2不能在thread1之前运行?为什么每个线程不能在另一个线程有机会运行到获取互斥锁的行之前完成它的循环几次呢

如果希望执行以可预测的方式在两个线程之间切换,则需要使用信号量、条件变量或其他机制
/* A flag that indicates whose turn it is. */
char tanked = 0;

void* thread_1_proc(void*)
{
    while(1) { //make it work forever
        pthread_mutex_lock(&mu);  //lock the mutex
        if(!tanked) { // is it my turn?
            cout << "tanking\n";
            for(int i=0; i<5; i++)
                bucket[i] = rand();  //actually, rand() returns int, doesn't matter
            tanked = 1;
        }
        pthread_mutex_unlock(&mu); // unlock the mutex
    }
}

void* thread_2_proc(void*)
{
    while(1) {
        pthread_mutex_lock(&mu);
        if(tanked) { // is it my turn?
            cout << "reading\n";
            for(int i=0; i<5; i++)
                cout << bucket[i] << " ";  //read each element in the bucket
            tanked = 0;
        }
        pthread_mutex_unlock(&mu); // unlock the mutex
    }
}