Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/163.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么这个互斥代码不能按预期工作?_C++_Pthreads_Mutex - Fatal编程技术网

C++ 为什么这个互斥代码不能按预期工作?

C++ 为什么这个互斥代码不能按预期工作?,c++,pthreads,mutex,C++,Pthreads,Mutex,关于这个话题的帖子和答案乱七八糟,但似乎没有一个能很好地模拟我的问题。在谷歌搜索stackoverflow之后,我不太明白我的问题的答案 我有两条线,一条主线和一条从线。在经过某个点之前,从站需要等待主站,因此我创建了一个互斥锁作为全局变量: pthread_mutex_t lock; pthread_cond_t cond = PTHREAD_COND_INITIALIZER; pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; int fla

关于这个话题的帖子和答案乱七八糟,但似乎没有一个能很好地模拟我的问题。在谷歌搜索stackoverflow之后,我不太明白我的问题的答案

我有两条线,一条主线和一条从线。在经过某个点之前,从站需要等待主站,因此我创建了一个互斥锁作为全局变量:

pthread_mutex_t lock;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
int flag = 0;
pthread_mutex_lock(&lock);
flag = 1;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);
然后在主线程的初始化过程中,在从线程有机会访问它之前,我锁定了它:

在主线程中初始化:

pthread_mutex_lock(&lock)
//master do something AAA
sem_post(data_ready);
//master do something BBB
sem_wait(slave_done);  //master may sleep here, and maybe interrupted by signal, need to handle that
//master do something CCC
然后在奴隶中,等待主人的时候,我会这样做:

奴隶必须在这里等待:

pthread_mutex_lock(&lock);
pthread_mutex_unlock(&lock);
同时,回到主人那里,我有这样一句话,是时候“释放”被阻止等待的奴隶了:

pthread_mutex_unlock(&lock);
pthread_mutex_lock(&lock);
(注意:主机的锁定/解锁顺序相反。)

基于我对互斥锁的理解,我认为从机会撞上锁,然后卡在那里等待主机解锁,然后立即再次锁定。就时间而言,从机将需要很长时间(保证)才能再次回到这里,因此主机将有很多时间重新锁定它。类似地,主人在一段时间内不会再回到这里,我们不必担心主人或奴隶会把另一个打回到这些检查站

当它没有像预期的那样工作时,我抛出了一些printf来确认主锁是否解锁,然后在从锁解锁之前重新锁定互斥锁。我的理解是,从机在主机到达那里进行解锁和(重新)锁定之前很久就请求了锁,并且无论主机解锁和(重新)锁定之间的时间有多短,从机应该仍然能够锁定互斥锁,因为他已经“排队”等待了

然而,我看到的情况是,主控解锁互斥锁,然后立即重新锁定互斥锁,即使奴隶被耐心地阻止,等待机会锁定互斥锁

以下是包含printf的代码和生成的输出:

奴隶:

printf("slave thread starting lock sequence\n");fflush(stdout);
pthread_mutex_lock(&lock);
printf("slave thread intra lock sequence\n");fflush(stdout);
pthread_mutex_unlock(&lock);
printf("slave thread completed lock sequence\n");fflush(stdout);
大师:

printf("master thread starting lock sequence\n");fflush(stdout);
pthread_mutex_unlock(&lock);
printf("master thread intra lock sequence\n");fflush(stdout);
pthread_mutex_lock(&lock);
printf("master thread completed lock sequence\n");fflush(stdout);
下面是我所看到的输出:

从线程启动锁定序列

。。。然后,从机被阻塞时,经过一段时间(几秒钟),最后出现:

主线程开始锁定序列

主线程内部锁定序列

主线程已完成锁定序列

与此同时,奴隶没有进一步的进步,他们永远被封锁。我本以为他会阻止主人重新锁定,应该吐出他的指纹,表明他已经前进了。这个输出清楚地表明被阻止的奴隶没有机会锁定互斥锁,即使他耐心地排队等待轮到他


那么,关于互斥体和锁定/解锁,我遗漏了什么呢


-gt-

正如对您的问题的评论中所指出的,pthreads互斥不能保证公平性

此作业的正确工具是共享标志变量,由互斥锁保护,并使用条件变量等待:

pthread_mutex_t lock;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
int flag = 0;
pthread_mutex_lock(&lock);
flag = 1;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);
从机等待标志:

pthread_mutex_lock(&lock);
while (!flag)
    pthread_cond_wait(&cond, &lock);
pthread_mutex_unlock(&lock);
当主机想要释放从机时,它设置标志并向条件变量发送信号:

pthread_mutex_t lock;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
int flag = 0;
pthread_mutex_lock(&lock);
flag = 1;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);
(请注意,当在
pthread\u cond\u wait()
中被阻塞时,互斥锁不会被保持)

当它没有像预期的那样工作时,我抛出了一些printf来确认主锁是否解锁,然后在从锁解锁之前重新锁定互斥锁。我的理解是,从机在主机到达那里进行解锁和(重新)锁定之前很久就请求了锁,并且无论主机解锁和(重新)锁定之间的时间有多短,从机应该仍然能够锁定互斥锁,因为他已经“排队”等待了

没有理由对线程公平,如果你虐待他们,他们不会向工会申诉。但有理由让整个系统尽可能快地完成尽可能多的工作。停止一个线程来启动另一个线程会对性能产生显著的负面影响,因为新线程在所有缓存都处于冷态的情况下启动,当您切换回时也会发生同样的情况


您的工作是确保您的代码在执行时能够完成您希望它完成的工作。调度程序将尝试尽快完成工作,只是偶尔向公平性点头。

也许您可以在信号量之后对问题进行建模,我发现这通常更容易理解和实现。类似于下面的伪代码示例

//before create slave thread, create semaphore first
sem_t data_ready, slave_done;
sem_init(&data_ready, 0);
sem_init(&slave_done, 0);
在主线程中:

pthread_mutex_lock(&lock)
//master do something AAA
sem_post(data_ready);
//master do something BBB
sem_wait(slave_done);  //master may sleep here, and maybe interrupted by signal, need to handle that
//master do something CCC
在从线程中:

//slave do something DDD
sem_wait(&data_ready); //slave may sleep here, and maybe interrupted by signal, need to handle that
//slave do something EEE
sem_post(&slave_done);
//slave do something FFF

您可能会发现执行顺序应该是AAA[BBB/DDD]EEE[FFF/CCC],它确保master->AAA在slave->EEE之前,后者在master->CCC之前运行。

重复的。Pthreads不能保证公平性。“那么,关于互斥体和锁定/解锁,我遗漏了什么呢?”从快速浏览中,听起来好像你在试图预测行为,但可能对调度程序的工作方式做出了假设。什么操作系统,哪个调度程序?我想我缺少的是Raymond指出的“缺乏公平性保证”。所以这不是我想象的“先到先得”。换句话说,仅仅因为从机已经排队等待锁定互斥锁,这并不能阻止主机在从机有机会之前再次锁定互斥锁。我相信这就是我所缺少的。Raymond,这听起来对吗?对于您想要实现的类型,通过条件变量发送信号是经典的pthreads方法。只需阅读pthread_cond_signal()的手册页。在我的Debian衍生系统上,pthreads手册页可以通过执行“sudo apt install glibc doc”来获得。