Как убедиться, что другие потоки завершены, прежде чем выполнять какое-либо действие

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

void *search_thread_func(void *threadArgs)
{
printf("\n");
//pthread_mutex_lock(&mutex);
int count = 0;
int matches = 0;
int matches_this_line = 0;
int lines = 0;
int inputLines = 0;
int tid;
int *wbPtr;
//char *buffer;
char *sharedBuffer;
char *writeBuffer;
char* string;
string = ((struct st_args*)threadArgs)->string;
tid = ((struct st_args*)threadArgs)->threadId;
wbPtr = ((struct st_args*)threadArgs)->wBufPtr;
//buffer = ((struct st_args*)threadArgs)->threadBuffer;
sharedBuffer = ((struct st_args*)threadArgs)->sharedBuffer;
writeBuffer = ((struct st_args*)threadArgs)->writeBuffer;
//printf("Thread %d\n",(int)tid);
printf("Searching for %s\n", string);

//printf("%d\n", (int)sharedBuffer);
while(sharedBuffer[count] != NULL)
{
    //printf("%c", sharedBuffer[count]);
    count++;
    if(sharedBuffer[count] == '\n')
    {
        inputLines++;
    }
}

printf("\n");
//pthread_mutex_unlock(&mutex);


char *token;
char *temp = malloc(count*sizeof(char));
memcpy(temp, sharedBuffer, count);
token = strtok(temp, "\n");

while(token != NULL)
{
    printf("%s\n", token);

    char *q = strstr(token, string);
    if(q != NULL)
    {
        matches_this_line++;
        lines++;

        for(char *r = q; r != NULL; r= strstr(r+strlen(string), string))
        {
            matches++;
        }
        pthread_mutex_lock(&mutex);
        for(int j = 0; j < strlen(token); j++)
        {
            writeBuffer[*wbPtr] = token[j];
            *wbPtr = *wbPtr + 1;    
        }
        writeBuffer[*wbPtr] = '\n';
        *wbPtr = *wbPtr + 1;
        pthread_mutex_unlock(&mutex);

    }

    token = strtok(NULL, "\n");
}

printf("lines %d, matches %d\n", lines, matches);

printBuffer(writeBuffer, *wbPtr);

free(temp);
printf("\n");
}

void *write_thread_func(void *threadArgs)
{
printf("write func\n");
char *writeBuffer;
int * wbPtr;
FILE* wFP;
writeBuffer = ((struct wt_args*)threadArgs)->writeBuffer;
wFP = ((struct wt_args*)threadArgs)->wFP;
wbPtr = ((struct st_args*)threadArgs)->wBufPtr;
printf("wbPtr = %d\n", wbPtr);
printf("*wbPtr = %d\n", *wbPtr);
//printf("wb loc = %d\n", writeBuffer);

}

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


person Danzo    schedule 06.03.2014    source источник


Ответы (1)


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

Есть способы добиться того же самого с семафорами (например, сделать так, чтобы каждый производитель отправил семафор один раз, а потребитель ждал N раза, где N — количество производителей), но этот тип дизайна требует, чтобы ваш потребитель знал больше деталей (например, сколько производителей), возможно, это не его дело.

person R.. GitHub STOP HELPING ICE    schedule 07.03.2014
comment
Кроме того, семафоры являются общесистемными, а не специфическими для процесса, поэтому вы можете столкнуться с проблемами, если запущено более одной копии вашей программы. - person user3303729; 07.03.2014
comment
@ user3303729: Нет, это проблема только в том случае, если (1) вы используете семафоры sysv или именованные семафоры POSIX и (2) вам не удается сгенерировать для них уникальное имя. Использование анонимных локальных семафоров POSIX (sem_init) является предпочтительным способом. - person R.. GitHub STOP HELPING ICE; 07.03.2014