按特定顺序执行 pthreads?

Execution of pthreads in particular order?

我一直在尝试编写一个程序(用于学习),其中将有两个线程(AB)并且两个线程应该一个接一个地执行。例如,如果线程只是 display/prints Thread AThread B,那么它们应该永远以该特定顺序打印。

期望的输出是

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

我写的程序使用conditional variables进行同步。我已经厌倦了 mutexsemaphore,但它们确实保证互斥性,但它们不按特定顺序打印信息。我知道这个问题与调度程序的线程 scheduling 有关,刚刚释放互斥锁的线程可能会立即再次锁定它。有关详细信息,请参阅 link 的 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 秒)后停止打印。我无法在我的代码中找到错误。如果有人指导我使用其他解决方案以更有效和标准的方法实现同样的事情(如果有其他标准和有效的方法来解决此类问题陈述),那就太好了。

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:

The pthread_cond_broadcast() or pthread_cond_signal() functions may be called by a thread whether or not it currently owns the mutex that threads calling pthread_cond_wait() or pthread_cond_timedwait() have associated with the condition variable during their waits; however, if predictable scheduling behavior is required, then that mutex shall be locked by the thread calling pthread_cond_broadcast() or pthread_cond_signal().