C / Linux: чередование потоков - PullRequest
0 голосов
/ 17 апреля 2020

Итак, у меня есть этот код:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <semaphore.h>

#define nr_threads 3
sem_t semaphores[nr_threads];
typedef struct {
    int id;
    char *word;
}th_struct;

void *thread_function(void *arg)
{
    th_struct *th_data = (th_struct *) arg; 

    sem_wait(&semaphores[th_data->id]);
        printf("[thread#%d] %s\n", th_data->id, th_data->word);
    sem_post(&semaphores[th_data->id + 1]);
    return NULL;
}

int main(int argc, char **argv)
{
    pthread_t tid[nr_threads];
    th_struct th_data[nr_threads];

    for(int i = 0; i < nr_threads; i++){
        if (sem_init(&semaphores[i], 0, 1) != 0){
            perror("Could not init semaphore");
            return -1;
        }
    }

    sem_post(&semaphores[0]);

    for(int i = 0; i < nr_threads; i++){
        th_data[i].id = i;
        th_data[i].word = argv[i + 1];
        pthread_create(&tid[i], NULL, thread_function, &th_data[i]);
    }

    for(int i = 0; i < nr_threads; i++){
        pthread_join(tid[i], NULL);
    }

    for(int i = 0; i < nr_threads; i++)
        sem_destroy(&semaphores[i]);

    return 0;
}

Я даю из командной строки 3 слова, например «один два три», и каждый поток печатает одно слово, синхронизированное, так что порядок будет всегда правильно.

Я новичок в потоках и семафорах, и мой мозг в настоящее время используется для sem_wait (sem) и после sem_post (sem), где sem - это тот же семафор. То, что я спрашиваю, является полным объяснением того, почему этот код работает и как он работает. Почему семафоры инициализируются с 0 разрешениями? Почему есть sem_post (first_semaphore)? Я очень смущен.

Ответы [ 2 ]

2 голосов
/ 17 апреля 2020

Прежде всего, в этом коде есть ошибка ...

После того, как он выполнит свою работу, каждый поток безоговорочно вызывает sem_post() на семафоре следующего потока. Следовательно, третий поток попытается получить доступ к semaphores[3], который не существует.

Теперь, что происходит (при условии, что ошибки не было), это:

  • 3 Семафоры создаются и инициализируются так, что они немедленно блокируются
  • 3 потока создаются, каждый вызывает sem_wait() и блокируется (потому что семафоры инициализируются в 0)
  • После того, как поток завершил это задание, оно вызывает sem_post() на семафоре следующего, который затем возвращается из sem_wait()

Это базовая идея c, но чтобы ее запустить, кто-то должен вызвать sem_post() для первого семафора. Так вот почему в main () есть sem_post(&semaphores[0]).

1 голос
/ 17 апреля 2020

Примечание: это скорее длинный комментарий, а не полный ответ.

Мне нравится думать о семафоре как о блокирующей очереди безинформативных токенов. count семафора - это число токенов в очереди.

С этой точки зрения основной поток в вашей программе создает один токен (из ничего, потому что токен равен ничего), и он передает токен первому рабочему потоку, вызывая sem_post(&semaphores[0]);.

Первый рабочий может выполнить свою работу после извлечения токена из своей входной очереди (то есть, когда sem_wait(&semaphores[th_data->id]); возвращается. И после того, как он завершил свою работу, он передает токен следующему потоку: sem_post(&semaphores[th_data->id + 1]);

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