По какой-то причине я думал, что вызов pthread_exit(NULL)
в конце основной функции гарантирует, что все запущенные потоки (по крайней мере созданные в основной функции) закончатся до того, как main
сможет выйти. Однако, когда я запускаю этот код ниже, не вызывая две функции pthread_join
(в конце main
), я явно получаю ошибку сегментации, которая, кажется, происходит, потому что функция main
была завершена до того, как два потока завершат их и поэтому буфер char недоступен. Однако, когда я включаю эти два вызова функции pthread_join
в конце main
, он работает так, как должен. Чтобы гарантировать, что main
не будет выходить до завершения всех запущенных потоков, необходимо ли явно вызывать pthread_join
для всех потоков, инициализированных непосредственно в main
?
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <assert.h>
#include <semaphore.h>
#define NUM_CHAR 1024
#define BUFFER_SIZE 8
typedef struct {
pthread_mutex_t mutex;
sem_t full;
sem_t empty;
char* buffer;
} Context;
void *Reader(void* arg) {
Context* context = (Context*) arg;
for (int i = 0; i < NUM_CHAR; ++i) {
sem_wait(&context->full);
pthread_mutex_lock(&(context->mutex));
char c = context->buffer[i % BUFFER_SIZE];
pthread_mutex_unlock(&(context->mutex));
sem_post(&context->empty);
printf("%c", c);
}
printf("\n");
return NULL;
}
void *Writer(void* arg) {
Context* context = (Context*) arg;
for (int i = 0; i < NUM_CHAR; ++i) {
sem_wait(&context->empty);
pthread_mutex_lock(&(context->mutex));
context->buffer[i % BUFFER_SIZE] = 'a' + (rand() % 26);
float ranFloat = (float) rand() / RAND_MAX;
if (ranFloat < 0.5) sleep(0.2);
pthread_mutex_unlock(&(context->mutex));
sem_post(&context->full);
}
return NULL;
}
int main() {
char buffer[BUFFER_SIZE];
pthread_t reader, writer;
Context context;
srand(time(NULL));
int status = 0;
status = pthread_mutex_init(&context.mutex, NULL);
status = sem_init(&context.full,0,0);
status = sem_init(&context.empty,0, BUFFER_SIZE);
context.buffer = buffer;
status = pthread_create(&reader, NULL, Reader, &context);
status = pthread_create(&writer, NULL, Writer, &context);
pthread_join(reader,NULL); // This line seems to be necessary
pthread_join(writer,NULL); // This line seems to be necessary
pthread_exit(NULL);
return 0;
}
Если это так, как я могу обработать случай, когда будет создано много идентичных потоков (например, в коде ниже) с использованием одного и того же идентификатора потока? В этом случае, как я могу убедиться, что все потоки будут завершены до выхода main
? Должен ли я иметь массив идентификаторов NUM_STUDENTS pthread_t
, чтобы иметь возможность сделать это? Думаю, я мог бы сделать это, разрешив потокам Student семафор, а затем позволить функции main
ждать на этом семафоре, но действительно ли нет более простого способа сделать это?
int main()
{
pthread_t thread;
for (int i = 0; i < NUM_STUDENTS; i++)
pthread_create(&thread,NULL,Student,NULL); // Threads
// Make sure that all student threads have finished
exit(0);
}