Выполнение pthreads в определенном порядке? - PullRequest
0 голосов
/ 27 апреля 2019

Я пытаюсь написать программу (для обучения), в которой будет два потока (A и B), и оба потока должны выполняться один за другим. Например, если потоки просто отображают / печатают Thread A и Thread B, то они должны печататься в этом конкретном порядке навсегда.

Желаемый результат:

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

Программа, которую я написал, использует conditional variables для синхронизации. Я устал mutex и semaphore, но они гарантируют взаимную исключительность, но не печатают информацию в определенном порядке. Я понимаю, что проблема связана с scheduling потоков планировщиком, и вполне возможно, что поток, который только что освободил мьютекс, может немедленно снова заблокировать его. См. Эту ссылку для ссылка для получения дополнительной информации.

#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 Ответ

2 голосов
/ 27 апреля 2019

Уведомления переменной условия теряются, когда ни один поток не ожидает в pthread_cond_wait и ложных пробуждений , поэтому код должен скорее ожидать изменения общего состояния.

Рабочий пример:

#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().

...