Как сделать так, чтобы pthread работал правильно, используя pthread_cond_signal и pthread_cond_wait? - PullRequest
3 голосов
/ 23 января 2012

Попытка реализовать двух параллельных рабочих. После формирования данных мне нужно сказать работнику взять данные и обработать их. Вот код:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>

void *worker(void *data);

struct worker_data_t
{
    pthread_t thread_id;
    pthread_mutex_t mutex;
    pthread_cond_t cond;
    long id, data;
};

struct worker_data_t *workers_data;

int main(int argc, char **argv)
{
    int cpus = sysconf(_SC_NPROCESSORS_ONLN);
    if (cpus < 1)
        cpus = 1;

    workers_data = (struct worker_data_t *)malloc(cpus * sizeof(struct worker_data_t));
    int ret_val[cpus];

    for (int i = 0; i < cpus; i++)
    {
        pthread_mutex_init(&workers_data[i].mutex, NULL);
        pthread_cond_init(&workers_data[i].cond, NULL);
        workers_data[i].id = i;
    }

    for (int i = 0; i < cpus; i++)
        ret_val[i] = pthread_create(&workers_data[i].thread_id, NULL, worker, &workers_data[i]);

    pthread_mutex_lock(&workers_data[0].mutex);
    pthread_cond_signal(&workers_data[0].cond);
    pthread_mutex_unlock(&workers_data[0].mutex);

    pthread_mutex_lock(&workers_data[0].mutex);
    pthread_cond_signal(&workers_data[0].cond);
    pthread_mutex_unlock(&workers_data[0].mutex);

    for (int i = 0; i < cpus; i++)
        pthread_join(workers_data[i].thread_id, NULL);

    return 0;
}

void *worker(void *data)
{
    struct worker_data_t d = *((struct worker_data_t*)(data));
    printf("Thread %d started\n", d.id);
    for (;;)
    {
        pthread_mutex_lock(&workers_data[d.id].mutex);
        pthread_cond_wait(&workers_data[d.id].cond, &workers_data[d.id].mutex);
        printf("catch!\n");
        pthread_mutex_unlock(&workers_data[d.id].mutex);
    }
}

После уведомления работника с помощью pthread_cond_signal ничего не происходит. Если я поставлю sleep (1) перед каждым блоком pthread_cond_signal, это сработает.

Что нужно сделать, чтобы он работал без сна?

Ответы [ 2 ]

2 голосов
/ 23 января 2012

Как сказал Р. и как он должен был сделать в ответе, вам нужен предикат .Это то, что вы проверяете, чтобы убедиться, что условие истинно.

В вашем случае это должна быть простая переменная, защищенная workers_data[0].mutex.

Затем в вашем работнике вы блокируетемьютекс, как вы уже делаете, затем проверьте предикат.Если предикат верен, вам не нужно ждать условия, поэтому не надо.Просто иди делай то, что тебе нужно.Если предикат имеет значение false, тогда подождите условие.

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

1 голос
/ 23 января 2012

Сигнал, генерируемый pthread_cond_signal(), теряется, если на condvar, на который ссылается этот вызов, нет потоков, заблокированных.Весьма вероятно, что произойдет следующее:

  1. main() вызовы потока pthread_create()
  2. main() поток выполнит 1 или более блоков блокировки-сигнала-разблокировки
  3. дочерние потоки получают процессорное время и блокируются на pthread_cond_wait().Сигнал уже потерян, поэтому он никогда не будет разбужен

Не определено, получает ли поток ЦП сразу после вызова pthread_create().Когда вы делаете sleep(1) перед тем, как подавать сигналы, вы даете возможность рабочим потокам исполниться и начать слушать их condvars.Это один из способов решения проблемы.Тем не менее, вы можете захотеть реализовать какую-то проверку готовности , чтобы убедиться, что работник ждет и ваш сигнал не потерян (создайте другой condvar и сообщите его, например, когда работник готов).Другой способ - использовать семафоры.

Также имейте в виду, что pthread_join() никогда не вернется в вашу программу, потому что у рабочих нет возможности выйти из бесконечного цикла.Также желательно проверять каждый pthread_...() возврат на наличие ошибки, особенно когда вы исследуете какое-то неожиданное поведение программы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...