pthread_cond_wait 使用循环时不唤醒
pthread_cond_wait donst wake-up when using loop
我是线程新手
我想使用 ptherad_cond_signal & pthread_cond_wait
检查一些条件
我有这段代码作为示例:
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int x = 0;
void* f1(void *arg){
for (int i = 0; i < 10; i++)
{
pthread_mutex_lock(&lock);
x += 10;
printf("%d\n", x);
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);
}
return NULL;
}
void* f2(void* arg){
pthread_mutex_lock(&lock);
while (x < 40)
{
pthread_cond_wait(&cond, &lock);
}
x -= 40;
pthread_mutex_unlock(&lock);
return NULL;
}
int main(int argc, char *args[]){
pthread_t p1, p2;
pthread_create(&p2, NULL, f2, NULL);
pthread_create(&p1, NULL, f1, NULL);
pthread_exit(NULL);
return 0;
}
结果:
10
20
30
40
50
60
70
80
90
100
但我预计:
10
20
30
40
10
20
30
40
50
60
为什么在pthread_cond_signal之后,函数f2没有继续?
好像在f1的for循环中,在pthread_cond_wait唤醒
之前再次加锁
您的第一个问题是 main
创建了两个线程,但可能会在其他两个线程完成之前退出(并退出您的程序)。也许 Linux 构建中的线程存在细微差别,等待所有线程完成,然后在 main returns 时退出进程。我总是忘记这里的规则,但这是 main
等待子线程完成的首选模式。这是一个简单的改变
int main(int argc, char *args[]){
pthread_t p1, p2;
pthread_create(&p2, NULL, f2, NULL);
pthread_create(&p1, NULL, f1, NULL);
// wait for both threads to complete
pthread_join(&p1, NULL);
pthread_join(&p2, NULL);
return 0;
}
回到原来的问题。
在上下文切换到 f2
之前,没有什么可以阻止 f1
递增到 100。
听起来你想要的是 f1
将 X 递增到 40,然后等待 f2
将其降回原位,然后再继续递增间隔直到 60。
您可以轻松地在两个线程中使用您的条件变量来通知更改并在另一个线程上等待。
我已经重构了您的一些代码,因此我不必一遍又一遍地重写同一个块。但它仍然主要是您的原始代码。
void IncrementX(int val)
{
pthread_mutex_lock(&lock);
x += 10;
printf("%d\n", x);
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);
}
void WaitForX(int target, int gt)
{
pthread_mutex_lock(&lock);
while ((x >= target && gt) || (x < target && !gt))
{
pthread_cond_wait(&cond, &lock);
}
pthread_mutex_unlock(&lock);
}
void* f1(void *arg){
// increment to 40
for (int i = 0; i < 4; i++)
{
IncrementX(10);
}
WaitForX(40, 0); // wait for X to drop below 40
// increment back to 60
for (int i = 0; i < 6; i++)
{
IncrementX(10);
}
return NULL;
}
void* f2(void* arg){
WaitForX(40, 1); // wait for X to go to 40 or above
IncrementX(-40);
return NULL;
}
我是线程新手 我想使用 ptherad_cond_signal & pthread_cond_wait 检查一些条件 我有这段代码作为示例:
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int x = 0;
void* f1(void *arg){
for (int i = 0; i < 10; i++)
{
pthread_mutex_lock(&lock);
x += 10;
printf("%d\n", x);
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);
}
return NULL;
}
void* f2(void* arg){
pthread_mutex_lock(&lock);
while (x < 40)
{
pthread_cond_wait(&cond, &lock);
}
x -= 40;
pthread_mutex_unlock(&lock);
return NULL;
}
int main(int argc, char *args[]){
pthread_t p1, p2;
pthread_create(&p2, NULL, f2, NULL);
pthread_create(&p1, NULL, f1, NULL);
pthread_exit(NULL);
return 0;
}
结果:
10
20
30
40
50
60
70
80
90
100
但我预计:
10
20
30
40
10
20
30
40
50
60
为什么在pthread_cond_signal之后,函数f2没有继续?
好像在f1的for循环中,在pthread_cond_wait唤醒
您的第一个问题是 main
创建了两个线程,但可能会在其他两个线程完成之前退出(并退出您的程序)。也许 Linux 构建中的线程存在细微差别,等待所有线程完成,然后在 main returns 时退出进程。我总是忘记这里的规则,但这是 main
等待子线程完成的首选模式。这是一个简单的改变
int main(int argc, char *args[]){
pthread_t p1, p2;
pthread_create(&p2, NULL, f2, NULL);
pthread_create(&p1, NULL, f1, NULL);
// wait for both threads to complete
pthread_join(&p1, NULL);
pthread_join(&p2, NULL);
return 0;
}
回到原来的问题。
在上下文切换到 f2
之前,没有什么可以阻止 f1
递增到 100。
听起来你想要的是 f1
将 X 递增到 40,然后等待 f2
将其降回原位,然后再继续递增间隔直到 60。
您可以轻松地在两个线程中使用您的条件变量来通知更改并在另一个线程上等待。
我已经重构了您的一些代码,因此我不必一遍又一遍地重写同一个块。但它仍然主要是您的原始代码。
void IncrementX(int val)
{
pthread_mutex_lock(&lock);
x += 10;
printf("%d\n", x);
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);
}
void WaitForX(int target, int gt)
{
pthread_mutex_lock(&lock);
while ((x >= target && gt) || (x < target && !gt))
{
pthread_cond_wait(&cond, &lock);
}
pthread_mutex_unlock(&lock);
}
void* f1(void *arg){
// increment to 40
for (int i = 0; i < 4; i++)
{
IncrementX(10);
}
WaitForX(40, 0); // wait for X to drop below 40
// increment back to 60
for (int i = 0; i < 6; i++)
{
IncrementX(10);
}
return NULL;
}
void* f2(void* arg){
WaitForX(40, 1); // wait for X to go to 40 or above
IncrementX(-40);
return NULL;
}