Почему моя семафорная блокировка не блокирует этот процесс, как ожидалось? (Многопоточность)

#c #arrays #multithreading #posix #semaphore

#c #массивы #многопоточность #posix #семафор

Вопрос:

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

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

 #include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/timeb.h>
#include <semaphore.h>
#include <stdbool.h>
#include <unistd.h>

#define MAX_SIZE 100000000
#define MAX_THREADS 16
#define RANDOM_SEED 8631
#define MAX_RANDOM_NUMBER 5000

// Global variables
long gRefTime; //For timing
int gData[MAX_SIZE]; //The array that will hold the data

int gThreadCount; //Number of threads
int gDoneThreadCount; //Number of threads that are done at a certain point. Whenever a thread is done, it increments this. Used with the semaphore-based solution
int gThreadMin[MAX_THREADS]; //The minimum value found by each thread
bool gThreadDone[MAX_THREADS]; //Is this thread done? Used when the parent is continually checking on child threads
int indices[MAX_THREADS][3];

// Semaphores
sem_t completed; //To notify parent that all threads have completed or one of them found a zero
sem_t mutex; //Binary semaphore to protect the shared variable gDoneThreadCount
int main(int argc, char *argv[]){

    pthread_t tid[MAX_THREADS];  
    pthread_attr_t attr[MAX_THREADS];

    int i, indexForZero, arraySize, min;

    // Code for parsing and checking command-line arguments
    if(argc != 4){
        fprintf(stderr, "Invalid number of arguments!n");
        exit(-1);
    }
    if((arraySize = atoi(argv[1])) <= 0 || arraySize > MAX_SIZE){
        fprintf(stderr, "Invalid Array Sizen");
        exit(-1);               
    }
    gThreadCount = atoi(argv[2]);               
    if(gThreadCount > MAX_THREADS || gThreadCount <=0){
        fprintf(stderr, "Invalid Thread Countn");
        exit(-1);               
    }
    indexForZero = atoi(argv[3]);
    if(indexForZero < -1 || indexForZero >= arraySize){
        fprintf(stderr, "Invalid index for zero!n");
        exit(-1);
    }

    GenerateInput(arraySize, indexForZero);

    CalculateIndices(arraySize, gThreadCount, indices); 


InitSharedVars();
SetTime();


// Initialize threads, create threads, and then make the parent wait on the "completed" semaphore 
// The thread start function is ThFindMinWithSemaphore

sem_init(amp;mutex, 0, 1);
sem_init(amp;completed, 0, 0);

for(i=0; i < gThreadCount; i  ){
pthread_attr_init(amp;attr[i]);
        pthread_create(amp;tid[i],amp;attr[i],ThFindMinWithSemaphore,amp;indices[i]);
}

sem_wait(amp;completed);

if(gThreadDone[i] == true amp;amp; gThreadMin[i] == min){ 
     for(i=0; i < gThreadCount; i  ){
    pthread_cancel(tid[i]);
    }
}


min = SearchThreadMin();
printf("Threaded FindMin with parent waiting on a semaphore completed in %ld ms. Min = %dn", GetTime(), min);
void* ThFindMinWithSemaphore(void *param) {
    int threadNum = ((int*)param)[0];

    int i;
    int startIndex = indices[threadNum][1];
    int endIndex = indices[threadNum][2];
    sem_wait(amp;completed);

    for (i = startIndex; i < endIndex; i  ) {   
        if (gData[i] < gThreadMin[threadNum]){
            gThreadMin[threadNum] = gData[i];
        }
        else if (gData[i] == 0){
            sem_post(amp;completed);
            pthread_exit(0);
        }
}

    sem_wait(amp;mutex);
    gDoneThreadCount  ;
    sem_post(amp;mutex);

    if (gDoneThreadCount == gThreadCount){
    sem_post(amp;completed);
    }
pthread_exit(0);
}
  

Обратите внимание, что это не весь код файла, который на самом деле находится в файле.

Я хочу, чтобы основная функция ожидала в строке, где написано sem_wait (amp;завершено). Цель состоит в том, чтобы дочерние потоки сигнализировали родительскому с помощью sem_post, когда каждый поток завершает поиск своего минимального значения, или один из потоков нашел ноль в массиве. Тогда в этот момент основная функция должна продолжиться после получения этого сигнала sem_post.

Как я понимаю, если семафор завершен, имеет нулевое значение, которое я инициализировал с помощью sem_init(amp;завершено, 0, 0), вызывающий sem_wait ожидает, пока не получит sem_post от одного из дочерних потоков. Похоже, что моя программа не выполняет ожидание, как ожидалось.

Комментарии:

1. Это не ответ, но… Мьютекс не является семафором. Вы должны использовать pthread_mutex для мьютекса.

2. Можете ли вы сказать, какое поведение вы наблюдаете? Для меня это выглядит как взаимоблокировка, поскольку «завершено» имеет начальное значение «0», и вы выполняете «sem_wait(amp;completed);» как в main (), так и в ThFindMinWithSemaphore(). Итак, «sem_wait(amp;completed);» в ThFindMinWithSemaphore() следует удалить.