Работа с pthreads и синхронизацией - PullRequest
0 голосов
/ 19 ноября 2018

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

Без этого неправильные числа могут быть добавлены в массив.

РЕДАКТИРОВАТЬ: кто-то предложил мне добавить pthread_barrier_wait (& after_filtering); в вызове filter_threads, и это, похоже, сработало. Теперь я знаю, что мне нужно добавить вызов ожидания как в main, так и в функцию filter, но я не совсем понимаю ход выполнения и как работают wait wait в main. Я знаю, что ожидание в функции потока гарантирует, что все потоки достигнут этой точки перед продолжением, но разве это не произойдет, как только потоки будут созданы? Это означает, что числа должны иметь значения 99 вместо 4, 3, 8, 1?

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

pthread_barrier_t before_filtering, after_filtering;
int nums[4] = {99, 99, 99, 99};
int arr[15] = {12, 5, 31, 8, 1, 6, 24, 4, 81, 42};

void filter(int i, int a[]){
    // Loop through the list
    int j;
    for (j = 0; j < 10; j++)
    {
        if (nums[i] == a[j])
            nums[i] = 0; 
    }
}

void *filter_threads(void *id){
    int *myid = (int *)id;
    printf("thread %d\n",*myid);
    pthread_barrier_wait(&before_filtering);
    filter(*myid, arr);
    pthread_barrier_wait(&after_filtering);
}

int main(void)
{
    pthread_t tids[3];
    int index[3];
    pthread_barrier_init(&before_filtering, NULL, 4);
    pthread_barrier_init(&after_filtering, NULL, 4);
    int i, j;

    for (i = 0; i < 3; i++)
    {   
        index[i] = i + 1;
        pthread_create(&tids[i], NULL, filter_threads, &index[i]);
    }

    // Cannot call any filter function without first populating nums
    nums[0] = 4;
    nums[1] = 3;
    nums[2] = 8;
    nums[3] = 1;

    pthread_barrier_wait(&before_filtering);
    filter(0, arr);
    pthread_barrier_wait(&after_filtering);

    // Add new numbers to arr...

    printf("New nums: ");
    for (i = 0; i < 4; i++)
        printf("%d, ", nums[i]);
    printf("\n");

    for (i = 0; i < 3; i++)
        pthread_join(tids[i], NULL);

    // Print new arr...

    pthread_barrier_destroy(&before_filtering);
    pthread_barrier_destroy(&after_filtering);
}

Я попытался добавить еще один вызов ожидания после фильтрации, но теперь программа просто зависает. Как мне это сделать?

1 Ответ

0 голосов
/ 19 ноября 2018

Барьер - это просто механизм, который гарантирует, что все N потоков достигнут определенной точки в коде перед продолжением.Следовательно, если вы вызываете pthread_barrier_init со счетчиком 4, любой поток, вызывающий pthread_barrier_wait на этом же барьере, не будет продолжаться до тех пор, пока три других потока также не вызовут pthread_barrier_wait.

Итак, как теперь показывает ваш код: три созданных потока после запуска выполнят pthread_barrier_wait(&before_filtering), где все они будут блокироваться, пока основной поток не выполнит sleep(3), а затем не инициализирует массив nums.Затем основной поток вызывает pthread_barrier_wait(&before_filtering).Это освобождает основной поток и все остальные для продолжения выполнения.

После выполнения функции filter каждый подпоток и основного потока должен выполнить pthread_barrier_wait(&after_filtering).В противном случае основной поток будет остановлен в ожидании трех других потоков, ожидающих на барьере.

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

...