我一直在尝试编写一个程序(用于学习),其中将有两个线程(A
和B
),并且两个线程应该一个接一个地执行。例如,如果线程仅显示/打印Thread A
和Thread B
,则它们应该永远按照该特定顺序打印。
所需的输出是
In Thread: thread1
In Thread: thread2
In Thread: thread1
In Thread: thread2
....
我编写的程序使用conditional variables
进行同步。我对mutex
和semaphore
感到厌倦,但他们确实保证了互斥,但它们没有按特定顺序打印信息。我知道问题与调度程序的scheduling
线程有关,刚刚释放互斥锁的线程有可能立即再次锁定它。有关更多信息,请参见link的链接。
#include <stdio.h>
#include <ctype.h>
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include <unistd.h>
#include <semaphore.h>
#include <pthread.h>
pthread_cond_t cond;
pthread_mutex_t mutex;
int thread1_ret = 0;
void *thread1(void *arg)
{
while (1) {
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond, &mutex);
printf("In Thread: %s\r\n", __func__);
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
}
thread1_ret = 5;
return &thread1_ret;
}
int thread2_ret = 0;
void *thread2(void *arg)
{
pthread_mutex_lock(&mutex);
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
while (1) {
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond, &mutex);
printf("In Thread: %s\r\n", __func__);
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
}
thread2_ret = 5;
return &thread2_ret;
}
int main(int argc, char *argv[])
{
pthread_t t1, t2;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
pthread_cond_init(&cond, NULL);
pthread_mutex_init(&mutex, NULL);
pthread_create(&t1, &attr, thread1, NULL);
pthread_create(&t2, &attr, thread2, NULL);
pthread_attr_destroy(&attr);
void *ret;
pthread_join(t1, &ret);
printf("Thread Returned: %d\r\n", *(int *)ret);
pthread_join(t2, &ret);
printf("Thread Returned: %d\r\n", *(int *)ret);
return 0;
}
我的程序运行正常,但过了一段时间(2-3秒)后它停止打印。我在代码中找不到错误。最好有人指导我用其他解决方案,以更有效和更标准的方法(如果还有其他标准和有效的方法来解决此类问题陈述)来实现同一目标。
答案 0 :(得分:2)
在pthread_cond_wait
和spurious wakes-ups中没有线程正在等待时,状态变量通知会丢失,因此代码必须等待共享状态的更改。
工作示例:
#include <stdio.h>
#include <ctype.h>
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include <unistd.h>
#include <semaphore.h>
#include <pthread.h>
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
unsigned state = 0;
int thread1_ret = 0;
void *thread1(void *arg)
{
unsigned state_copy;
pthread_mutex_lock(&mutex);
state_copy = state;
pthread_mutex_unlock(&mutex);
while(1) {
pthread_mutex_lock(&mutex);
while(state_copy == state)
pthread_cond_wait(&cond, &mutex);
state_copy = ++state;
printf("In Thread: %s\r\n", __func__);
pthread_mutex_unlock(&mutex);
pthread_cond_signal(&cond);
}
thread1_ret = 5;
return &thread1_ret;
}
int thread2_ret = 0;
void *thread2(void *arg)
{
unsigned state_copy;
pthread_mutex_lock(&mutex);
state_copy = ++state;
pthread_mutex_unlock(&mutex);
pthread_cond_signal(&cond);
while (1) {
pthread_mutex_lock(&mutex);
while(state_copy == state)
pthread_cond_wait(&cond, &mutex);
state_copy = ++state;
printf("In Thread: %s\r\n", __func__);
pthread_mutex_unlock(&mutex);
pthread_cond_signal(&cond);
}
thread2_ret = 5;
return &thread2_ret;
}
int main(int argc, char *argv[])
{
pthread_t t1, t2;
pthread_create(&t1, NULL, thread1, NULL);
pthread_create(&t2, NULL, thread2, NULL);
void *ret;
pthread_join(t1, &ret);
printf("Thread Returned: %d\r\n", *(int *)ret);
pthread_join(t2, &ret);
printf("Thread Returned: %d\r\n", *(int *)ret);
return 0;
}
请注意,上述代码在释放互斥锁后向条件变量 发信号。这是微优化,但是,如果在唤醒等待线程时需要FIFO顺序,则互斥锁必须在发信号时锁定。参见pthread_cond_signal
:
线程可以调用
pthread_cond_broadcast()
或pthread_cond_signal()
函数,无论它当前是否拥有调用pthread_cond_wait()
或pthread_cond_timedwait()
的线程与条件变量相关联的互斥量在他们的等待中;但是,如果需要可预测的调度行为,则该互斥锁应通过调用pthread_cond_broadcast()
或pthread_cond_signal()
的线程来锁定。