以特定顺序执行pthread?

时间:2019-04-27 18:37:38

标签: c multithreading synchronization pthreads

我一直在尝试编写一个程序(用于学习),其中将有两个线程(AB),并且两个线程应该一个接一个地执行。例如,如果线程仅显示/打印Thread AThread B,则它们应该永远按照该特定顺序打印。

所需的输出是

In Thread: thread1
In Thread: thread2
In Thread: thread1
In Thread: thread2
....

我编写的程序使用conditional variables进行同步。我对mutexsemaphore感到厌倦,但他们确实保证了互斥,但它们没有按特定顺序打印信息。我知道问题与调度程序的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秒)后它停止打印。我在代码中找不到错误。最好有人指导我用其他解决方案,以更有效和更标准的方法(如果还有其他标准和有效的方法来解决此类问题陈述)来实现同一目标。

1 个答案:

答案 0 :(得分:2)

pthread_cond_waitspurious 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()的线程来锁定。