我写了一个写了一个程序,它没有像我期望的那样工作。
我有两个主题:thread
触发器func
和anotherThread
触发器anotherFunc
。我想要做的是当cont
达到10
中的值func
时,anotherThread
使用pthread_cond_wait
和pthread_cond_signal
触发。奇怪的是,如果我取消注释sleep(1)
行,一切正常。我是线程的新手,我正在学习教程here,如果我在他们的示例中评论sleep
行,它也会中断。
我的问题是如何在没有任何sleep()
电话的情况下完成这项工作?如果我的代码中func
在pthread_mutex_lock
之后到达anotherFunc
会发生什么?我该如何控制这些东西?这是我的代码:
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
pthread_mutex_t myMutex;
pthread_cond_t cond;
pthread_attr_t attr;
int cont;
void *func(void*)
{
printf("func\n");
for(int i = 0; i < 20; i++)
{
pthread_mutex_lock(&myMutex);
cont++;
printf("%d\n", cont);
if(cont == 10)
{
printf("signal:\n");
pthread_cond_signal(&cond);
// sleep(1);
}
pthread_mutex_unlock(&myMutex);
}
printf("Done func\n");
pthread_exit(NULL);
}
void *anotherFunc(void*)
{
printf("anotherFunc\n");
pthread_mutex_lock(&myMutex);
printf("waiting...\n");
pthread_cond_wait(&cond, &myMutex);
cont += 10;
printf("slot\n");
pthread_mutex_unlock(&myMutex);
printf("mutex unlocked anotherFunc\n");
printf("Done anotherFunc\n");
pthread_exit(NULL);
}
int main(int argc, char *argv[])
{
pthread_t thread;
pthread_t anotherThread;
pthread_attr_init(&attr);
pthread_mutex_init(&myMutex, NULL);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
pthread_cond_init(&cond, NULL);
pthread_create(&anotherThread, &attr, anotherFunc, NULL);
pthread_create(&thread, &attr, func, NULL);
pthread_join(thread, NULL);
pthread_join(anotherThread, NULL);
printf("Done MAIN()");
pthread_mutex_destroy(&myMutex);
pthread_cond_destroy(&cond);
pthread_attr_destroy(&attr);
pthread_exit(NULL);
return 0;
}
很抱歉这篇文章很长,但我是新手,我很乐意学习。你也知道关于Linux上线程和网络的一些好的参考资料或课程/教程吗?我想学习创建一个聊天客户端,我听说我必须知道线程和网络。问题是我不知道我学到的东西还不错,因为我不知道我必须知道什么。
非常感谢你:)
答案 0 :(得分:9)
您的anotherThread
只是在没有先测试所需条件(计数器达到10)是否已经发生的情况下调用pthread_cond_wait
。这是不正确的逻辑,这将导致丢失唤醒问题:一个反复出现错误的名称,它会困扰错误编写的多线程程序。
条件变量是无状态的。如果在没有线程当前正在等待的条件上调用pthread_cond_signal
或pthread_cond_broadcast
,则该操作无效。它没有被记住。因此,您的信令线程可以非常快速地计数到10
,并在另一个线程到达pthread_cond_wait
调用之前发出条件变量的信号。
你需要一个pthread_cond_wait
的循环。必须检查条件以防它已经为真,这样线程就不会等待已经发生的唤醒。它应该是一个循环,因为唤醒可能是假的:只是因为线程通过pthread_cond_wait
并不意味着条件实际上是真的:
while (cont < 10)
pthread_cond_wait(&cond, &myMutex);
此外,不需要创建线程属性只是为了使线程可以连接。当您为创建属性使用空指针时,这是默认情况。 POSIX线程是可连接的,除非创建分离,或转换为与pthread_detach
分离。
另一件事:尽可能避免在持有互斥锁时调用pthread_cond_signal
。这不是不正确的,但它可能是浪费的,因为操作可能实际上必须调用OS内核来唤醒一个线程,因此你在整个系统调用中持有这个昂贵的互斥锁(当你真正需要它时)保护在应用程序中使用共享数据的一些机器指令。
答案 1 :(得分:2)
我不知道你的实际问题是什么(当它不起作用时会发生什么?)..
我看到一个主要问题,你没有处理spurious wakeups。
你需要能够表明条件真实的东西,例如布尔变量:
INIT:
signaled = false;
信号:
signaled = true;
pthread_cond_signal(&cond);
得到:
while (!signaled)
pthread_cond_wait(&cond, &myMutex);
答案 2 :(得分:1)
答案 3 :(得分:0)
这只是一个想法,但您也可以使用信号量来执行“触发”。我记得我刚刚工作的一个项目,我们做的是当我们的一个线程等待被触发时(使用sem_wait)它只是等待无限时间试图获得锁定(因此被取消了)调度程序的proc和节省宝贵的周期)。一旦主线程完成了他的计算,就会释放信号量,允许第二个线程进行计算。
这只是另一种选择。