Вы более чем усложняете вещи без причины, вам будет тяжело
придумывать нить, когда вы сами кладете камни на пути. Причина использовать
условные переменные предназначены для того, когда потоки должны быть синхронизированы, когда один
Поток может продолжить работу, только когда другой достиг некоторого состояния, и оба (или более потоков) должны
быть синхронизированным. В этом случае, однако, ни одна нить не зависит от других и
главный поток может с радостью ждать, пока все работники закончат, прежде чем что-то делать
полезно.
psmears указывает на некоторые проблемы в вашем коде. Я хотел бы остановиться на
этот ответ и покажет вам, как вы можете использовать темы для решения этой проблемы
из-за того, что это делает его слишком сложным (сигналы не нужны, мьютекс не нужен).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <errno.h>
struct thefiles {
char *name;
int linecount;
int fo_errno;
};
void *count_lines(void *args)
{
struct thefiles *data = args;
FILE *fp = fopen(data->name, "r");
if(fp == NULL)
{
data->linecount = -1; // signaling error
data->fo_errno = errno;
pthread_exit(0);
}
data->linecount = 0;
char line[1024];
char *nl;
while(fgets(line, sizeof line, fp))
{
nl = strchr(line, '\n');
if(nl)
data->linecount++;
}
// last line of file did not end in newline
if(nl == NULL)
data->linecount++;
fclose(fp);
pthread_exit(0);
}
int main(int argc, char **argv)
{
if(argc < 2)
{
fprintf(stderr, "usage: %s file [file ...]\n", argv[0]);
return 1;
}
struct thefiles *fls = calloc(argc - 1, sizeof *fls);
if(fls == NULL)
{
fprintf(stderr, "Not enough memory\n");
return 1;
}
pthread_t *ths = calloc(argc - 1, sizeof *ths);
if(ths == NULL)
{
free(fls);
fprintf(stderr, "Not enough memory\n");
return 1;
}
for(int i = 0; i < argc - 1; ++i)
{
fls[i].name = argv[i+1];
pthread_create(ths + i, NULL, count_lines, fls + i);
}
int total = 0;
for(int i = 0; i < argc - 1; ++i)
{
pthread_join(ths[i], NULL);
if(fls[i].linecount == -1)
{
fprintf(stderr, "%s: %s: %s\n", argv[0], fls[i].name, strerror(fls[i].fo_errno));
continue;
}
printf("%4d %s\n", fls[i].linecount, fls[i].name);
total += fls[i].linecount;
}
printf("%4d total\n", total);
free(ths);
free(fls);
return 0;
}
Как видите, это намного проще, чем у вас, нет необходимости в сигналах и
переменные состояния и т. д., рабочие делают только одно: открывают
файл, посчитать строки, сохранить результат в аргументах, переданных в поток
и выход. Основной поток создает потоки, присоединяет их и печатает
Результаты:
$ ./b /etc/fstab a.c b.c aa
46 /etc/fstab
124 a.c
98 b.c
./b: aa: No such file or directory
268 total
$ wc -l /etc/fstab a.c b.c aa
46 /etc/fstab
124 a.c
98 b.c
wc: aa: No such file or directory
268 total
Конечно, это всего лишь простой пример, я бы основывался на этом примере, чтобы расширить
использование потоков, например, вычисление итогов по потокам
самих себя. В этом случае total
должен быть общим ресурсом, и вам потребуется
мьютекс, чтобы защитить его, попробуйте сначала реализовать это.