如何让线程等待变量更改?
How do I make a thread wait for a variable to change?
我希望函数 foo()
等待数组更新。结构 data
包含 foo()
方法的参数。我将 foo()
附加到一个线程,并且在 foo()
函数中有一个 while 循环,用于检查 updated
何时为 1
(这意味着 main()
函数已更改数组。它应该在发生这种情况时打印数组。
这不会打印任何东西;该程序永远停滞不前。我不太熟悉线程,所以我不知道这是否是正确的方法。
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
struct data {
int array[5];
int updated;
};
pthread_cond_t cv;
pthread_mutex_t mp;
pthread_condattr_t cattr;
int ret;
void* foo(void* da) {
struct data* d = (struct data*)da;
while (d->updated == 0) {
pthread_mutex_lock(&mp);
if (d->updated == 1) {
pthread_cond_wait(&cv, &mp);
printf("Updated: ");
for (int i = 0; i < 5; i++) {
printf("%d ", d->array[i]);
}
printf("\n");
d->updated = 0;
}
pthread_mutex_unlock(&mp);
}
pthread_exit(NULL);
}
int main(void) {
pthread_t thread;
pthread_attr_t attr;
void *status;
struct data temp;
temp.updated = 0;
ret = pthread_cond_init(&cv, NULL);
ret = pthread_cond_init(&cv, &cattr);
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
pthread_create(&thread, NULL, foo, (void *) &temp);
int rc = pthread_join(thread, &status);
if (rc) {
printf("ERROR; return code from pthread_join() is %d\n", rc);
exit(-1);
}
pthread_mutex_lock(&mp);
for (i = 0; i < 5; i++) {
temp.array[i] *= 2;
}
temp.updated = 1;
pthread_mutex_unlock(&mp);
pthread_exit(NULL);
}
编辑:
进行了答案中建议的更改后,这就是我现在的样子。它正在打印数组,但我希望它在数组更改时检测到(即每当 updated
设置为 true 时)。目前 foo
就像一个普通的非线程函数。
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
int array[5] = {0,0,0,0,0};
pthread_cond_t cv;
pthread_mutex_t mp;
int updated = 0;
pthread_cond_t cv2;
pthread_mutex_t mp2;
int donePrinting = 0;
void* foo(void* a) {
pthread_mutex_lock(&mp);
int* arr = *(int**)a;
while (1) {
while (updated == 0)
pthread_cond_wait(&cv, &mp);
printf("Updated: ");
for (int i = 0; i < 5; i++) {
printf("%d ", arr[i]);
}
printf("\n");
updated = 0;
pthread_mutex_lock(&mp2);
donePrinting = 1;
pthread_cond_signal(&cv2); // Signal to main that we are done printing
pthread_mutex_unlock(&mp2);
}
pthread_mutex_unlock(&mp);
pthread_exit(NULL);
}
void changeArray(void) {
pthread_mutex_lock(&mp);
int i;
for (i = 0; i < 5; i++) {
array[i] += 2;
}
updated = 1;
pthread_cond_signal(&cv);
pthread_mutex_unlock(&mp);
}
int main(void) {
pthread_t thread;
void *status;
pthread_cond_init(&cv, NULL);
pthread_cond_init(&cv2, NULL);
pthread_mutex_init(&mp, NULL);
pthread_mutex_init(&mp2, NULL);
pthread_create(&thread, NULL, foo, &array);
// """"""""""""
// Change the array
changeArray();
// Wait for the second thread to finish printing
pthread_mutex_lock(&mp2);
while (!donePrinting)
pthread_cond_wait(&cv2, &mp2);
changeArray();
donePrinting = 0;
pthread_mutex_unlock(&mp2);
return 0;
// Change the array again
// Wait for the second thread to finish printing
pthread_mutex_lock(&mp2);
while (!donePrinting)
pthread_cond_wait(&cv2, &mp2);
donePrinting = 0;
changeArray();
pthread_mutex_unlock(&mp2);
// """"""""""""""""
int rc = pthread_join(thread, &status);
if (rc) {
printf("ERROR; return code from pthread_join() is %d\n", rc);
exit(-1);
}
pthread_exit(NULL);
}
你需要在这个程序的某个点调用pthread_cond_signal
。
首先是台词
ret = pthread_cond_init(&cv, NULL);
ret = pthread_cond_init(&cv, &cattr);
错了。对同一个条件变量 cv
调用两次 pthread_cond_init
是没有意义的。另外,如果你使用cattr
,你应该先初始化它,然后再传递给pthread_cond_init
。如果你想使用默认条件变量属性,那么你应该简单地传递 NULL
而不是 &cattr
。你可能想做后者。在这种情况下,您应该简单地删除第二行并删除 cattr
.
的声明
另外,你必须在使用前初始化互斥量mp
,使用pthread_mutex_init
。
行
int rc = pthread_join(thread, &status);
将导致主线程等待第二个线程完成。然而,这永远不会发生,因为行
temp.updated = 1;
第二个线程正在等待,稍后在主线程中发生。因此,你应该移动
int rc = pthread_join(thread, &status);
行后:
temp.updated = 1;
此外,您应该在
行之后添加对 pthread_cond_signal
的调用
temp.updated = 1;
但在行之前
int rc = pthread_join(thread, &status);
以便第二个线程得到通知,它应该再次检查变量。
此外,在第二个线程中,行
while (d->updated == 0) {
是错误的,因为执行该行时您没有持有互斥锁。这会导致未定义的行为(由于共享变量上的竞争条件)。
因此,如果要保持d->updated == 0
循环条件,则必须移动
行
pthread_mutex_lock(&mp);
行前:
while (d->updated == 0) {
这意味着你将有两次重组你的循环,因为pthread_mutex_unlock
的位置也必须在正确的地方。
但是,我怀疑您保留 d->updated == 0
循环条件是否合适。如果它应该是一个无限循环,那么你可以写 for (;;)
或 while ( 1 )
来代替,这样你就不会遇到在循环条件下访问共享变量的问题。
关于您更新的代码,我相信这是该程序的工作版本,它可以完成您想要的一切:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
int array[5] = {0};
pthread_cond_t cv;
pthread_mutex_t mp;
int updated = 0;
int terminate = 0;
pthread_cond_t cv2;
pthread_mutex_t mp2;
int donePrinting = 0;
void* foo(void* a) {
pthread_mutex_lock(&mp);
int* arr = a;
while ( 1 ) {
while ( updated == 0 && terminate == 0 )
pthread_cond_wait(&cv, &mp);
if ( terminate )
break;
printf("Updated: ");
for (int i = 0; i < 5; i++) {
printf("%d ", arr[i]);
fflush( stdout );
}
printf("\n");
fflush( stdout );
updated = 0;
pthread_mutex_lock(&mp2);
donePrinting = 1;
pthread_cond_signal(&cv2); // Signal to main that we are done printing
pthread_mutex_unlock(&mp2);
}
pthread_mutex_unlock(&mp);
pthread_exit(NULL);
}
void changeArray(void) {
pthread_mutex_lock(&mp);
int i;
for (i = 0; i < 5; i++) {
array[i] += 2;
}
updated = 1;
pthread_cond_signal(&cv);
pthread_mutex_unlock(&mp);
}
int main(void) {
pthread_t thread;
void *status;
pthread_cond_init(&cv, NULL);
pthread_cond_init(&cv2, NULL);
pthread_mutex_init(&mp, NULL);
pthread_mutex_init(&mp2, NULL);
pthread_create(&thread, NULL, foo, (void*)&array);
// """"""""""""
// Change the array
changeArray();
// Wait for the second thread to finish printing
pthread_mutex_lock(&mp2);
while (!donePrinting)
pthread_cond_wait(&cv2, &mp2);
pthread_mutex_unlock(&mp2);
//reset donePrinting
pthread_mutex_lock(&mp2);
donePrinting = 0;
pthread_mutex_unlock(&mp2);
// Change the array again
changeArray();
// Wait for the second thread to finish printing
pthread_mutex_lock(&mp2);
while (!donePrinting)
pthread_cond_wait(&cv2, &mp2);
pthread_mutex_unlock(&mp2);
//reset doneprinting
pthread_mutex_lock(&mp2);
donePrinting = 0;
pthread_mutex_unlock(&mp2);
// Change the array a third time
changeArray();
// """"""""""""""""
// Wait for the second thread to finish printing
pthread_mutex_lock(&mp2);
while (!donePrinting)
pthread_cond_wait(&cv2, &mp2);
pthread_mutex_unlock(&mp2);
//send terminate request
pthread_mutex_lock(&mp);
terminate = 1;
pthread_cond_signal(&cv);
pthread_mutex_unlock(&mp);
int rc = pthread_join(thread, &status);
if (rc) {
printf("ERROR; return code from pthread_join() is %d\n", rc);
exit(-1);
}
pthread_exit(NULL);
}
我更改了程序,当处理完成并且没有任何东西要发送时,主线程向第二个线程发送终止请求。
我希望函数 foo()
等待数组更新。结构 data
包含 foo()
方法的参数。我将 foo()
附加到一个线程,并且在 foo()
函数中有一个 while 循环,用于检查 updated
何时为 1
(这意味着 main()
函数已更改数组。它应该在发生这种情况时打印数组。
这不会打印任何东西;该程序永远停滞不前。我不太熟悉线程,所以我不知道这是否是正确的方法。
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
struct data {
int array[5];
int updated;
};
pthread_cond_t cv;
pthread_mutex_t mp;
pthread_condattr_t cattr;
int ret;
void* foo(void* da) {
struct data* d = (struct data*)da;
while (d->updated == 0) {
pthread_mutex_lock(&mp);
if (d->updated == 1) {
pthread_cond_wait(&cv, &mp);
printf("Updated: ");
for (int i = 0; i < 5; i++) {
printf("%d ", d->array[i]);
}
printf("\n");
d->updated = 0;
}
pthread_mutex_unlock(&mp);
}
pthread_exit(NULL);
}
int main(void) {
pthread_t thread;
pthread_attr_t attr;
void *status;
struct data temp;
temp.updated = 0;
ret = pthread_cond_init(&cv, NULL);
ret = pthread_cond_init(&cv, &cattr);
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
pthread_create(&thread, NULL, foo, (void *) &temp);
int rc = pthread_join(thread, &status);
if (rc) {
printf("ERROR; return code from pthread_join() is %d\n", rc);
exit(-1);
}
pthread_mutex_lock(&mp);
for (i = 0; i < 5; i++) {
temp.array[i] *= 2;
}
temp.updated = 1;
pthread_mutex_unlock(&mp);
pthread_exit(NULL);
}
编辑:
进行了答案中建议的更改后,这就是我现在的样子。它正在打印数组,但我希望它在数组更改时检测到(即每当 updated
设置为 true 时)。目前 foo
就像一个普通的非线程函数。
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
int array[5] = {0,0,0,0,0};
pthread_cond_t cv;
pthread_mutex_t mp;
int updated = 0;
pthread_cond_t cv2;
pthread_mutex_t mp2;
int donePrinting = 0;
void* foo(void* a) {
pthread_mutex_lock(&mp);
int* arr = *(int**)a;
while (1) {
while (updated == 0)
pthread_cond_wait(&cv, &mp);
printf("Updated: ");
for (int i = 0; i < 5; i++) {
printf("%d ", arr[i]);
}
printf("\n");
updated = 0;
pthread_mutex_lock(&mp2);
donePrinting = 1;
pthread_cond_signal(&cv2); // Signal to main that we are done printing
pthread_mutex_unlock(&mp2);
}
pthread_mutex_unlock(&mp);
pthread_exit(NULL);
}
void changeArray(void) {
pthread_mutex_lock(&mp);
int i;
for (i = 0; i < 5; i++) {
array[i] += 2;
}
updated = 1;
pthread_cond_signal(&cv);
pthread_mutex_unlock(&mp);
}
int main(void) {
pthread_t thread;
void *status;
pthread_cond_init(&cv, NULL);
pthread_cond_init(&cv2, NULL);
pthread_mutex_init(&mp, NULL);
pthread_mutex_init(&mp2, NULL);
pthread_create(&thread, NULL, foo, &array);
// """"""""""""
// Change the array
changeArray();
// Wait for the second thread to finish printing
pthread_mutex_lock(&mp2);
while (!donePrinting)
pthread_cond_wait(&cv2, &mp2);
changeArray();
donePrinting = 0;
pthread_mutex_unlock(&mp2);
return 0;
// Change the array again
// Wait for the second thread to finish printing
pthread_mutex_lock(&mp2);
while (!donePrinting)
pthread_cond_wait(&cv2, &mp2);
donePrinting = 0;
changeArray();
pthread_mutex_unlock(&mp2);
// """"""""""""""""
int rc = pthread_join(thread, &status);
if (rc) {
printf("ERROR; return code from pthread_join() is %d\n", rc);
exit(-1);
}
pthread_exit(NULL);
}
你需要在这个程序的某个点调用pthread_cond_signal
。
首先是台词
ret = pthread_cond_init(&cv, NULL);
ret = pthread_cond_init(&cv, &cattr);
错了。对同一个条件变量 cv
调用两次 pthread_cond_init
是没有意义的。另外,如果你使用cattr
,你应该先初始化它,然后再传递给pthread_cond_init
。如果你想使用默认条件变量属性,那么你应该简单地传递 NULL
而不是 &cattr
。你可能想做后者。在这种情况下,您应该简单地删除第二行并删除 cattr
.
另外,你必须在使用前初始化互斥量mp
,使用pthread_mutex_init
。
行
int rc = pthread_join(thread, &status);
将导致主线程等待第二个线程完成。然而,这永远不会发生,因为行
temp.updated = 1;
第二个线程正在等待,稍后在主线程中发生。因此,你应该移动
int rc = pthread_join(thread, &status);
行后:
temp.updated = 1;
此外,您应该在
行之后添加对pthread_cond_signal
的调用
temp.updated = 1;
但在行之前
int rc = pthread_join(thread, &status);
以便第二个线程得到通知,它应该再次检查变量。
此外,在第二个线程中,行
while (d->updated == 0) {
是错误的,因为执行该行时您没有持有互斥锁。这会导致未定义的行为(由于共享变量上的竞争条件)。
因此,如果要保持d->updated == 0
循环条件,则必须移动
pthread_mutex_lock(&mp);
行前:
while (d->updated == 0) {
这意味着你将有两次重组你的循环,因为pthread_mutex_unlock
的位置也必须在正确的地方。
但是,我怀疑您保留 d->updated == 0
循环条件是否合适。如果它应该是一个无限循环,那么你可以写 for (;;)
或 while ( 1 )
来代替,这样你就不会遇到在循环条件下访问共享变量的问题。
关于您更新的代码,我相信这是该程序的工作版本,它可以完成您想要的一切:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
int array[5] = {0};
pthread_cond_t cv;
pthread_mutex_t mp;
int updated = 0;
int terminate = 0;
pthread_cond_t cv2;
pthread_mutex_t mp2;
int donePrinting = 0;
void* foo(void* a) {
pthread_mutex_lock(&mp);
int* arr = a;
while ( 1 ) {
while ( updated == 0 && terminate == 0 )
pthread_cond_wait(&cv, &mp);
if ( terminate )
break;
printf("Updated: ");
for (int i = 0; i < 5; i++) {
printf("%d ", arr[i]);
fflush( stdout );
}
printf("\n");
fflush( stdout );
updated = 0;
pthread_mutex_lock(&mp2);
donePrinting = 1;
pthread_cond_signal(&cv2); // Signal to main that we are done printing
pthread_mutex_unlock(&mp2);
}
pthread_mutex_unlock(&mp);
pthread_exit(NULL);
}
void changeArray(void) {
pthread_mutex_lock(&mp);
int i;
for (i = 0; i < 5; i++) {
array[i] += 2;
}
updated = 1;
pthread_cond_signal(&cv);
pthread_mutex_unlock(&mp);
}
int main(void) {
pthread_t thread;
void *status;
pthread_cond_init(&cv, NULL);
pthread_cond_init(&cv2, NULL);
pthread_mutex_init(&mp, NULL);
pthread_mutex_init(&mp2, NULL);
pthread_create(&thread, NULL, foo, (void*)&array);
// """"""""""""
// Change the array
changeArray();
// Wait for the second thread to finish printing
pthread_mutex_lock(&mp2);
while (!donePrinting)
pthread_cond_wait(&cv2, &mp2);
pthread_mutex_unlock(&mp2);
//reset donePrinting
pthread_mutex_lock(&mp2);
donePrinting = 0;
pthread_mutex_unlock(&mp2);
// Change the array again
changeArray();
// Wait for the second thread to finish printing
pthread_mutex_lock(&mp2);
while (!donePrinting)
pthread_cond_wait(&cv2, &mp2);
pthread_mutex_unlock(&mp2);
//reset doneprinting
pthread_mutex_lock(&mp2);
donePrinting = 0;
pthread_mutex_unlock(&mp2);
// Change the array a third time
changeArray();
// """"""""""""""""
// Wait for the second thread to finish printing
pthread_mutex_lock(&mp2);
while (!donePrinting)
pthread_cond_wait(&cv2, &mp2);
pthread_mutex_unlock(&mp2);
//send terminate request
pthread_mutex_lock(&mp);
terminate = 1;
pthread_cond_signal(&cv);
pthread_mutex_unlock(&mp);
int rc = pthread_join(thread, &status);
if (rc) {
printf("ERROR; return code from pthread_join() is %d\n", rc);
exit(-1);
}
pthread_exit(NULL);
}
我更改了程序,当处理完成并且没有任何东西要发送时,主线程向第二个线程发送终止请求。