C语言 C 中的 pthreads - pthread_exit
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3330048/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
pthreads in C - pthread_exit
提问by Siggi
For some reason I thought that calling pthread_exit(NULL)at the end of a main function would guarantee that all running threads (at least created in the main function) would finish running before maincould exit. However when I run this code below without calling the two pthread_joinfunctions (at the end of main) explicitly I get a segmentation fault, which seems to happen because the mainfunction has been exited before the two threads finish their job, and therefore the char bufferis not available anymore. However when I include these two pthread_joinfunction calls at the end of mainit runs as it should. To guarantee that mainwill not exit before all running threads have finished, is it necessary to call pthread_joinexplicitly for all threads initialized directly in main?
出于某种原因,我认为pthread_exit(NULL)在主函数末尾调用将保证所有正在运行的线程(至少在主函数中创建)将在main退出之前完成运行。但是,当我在不显式调用这两个pthread_join函数的情况下(在 末尾main)运行下面的代码时,我得到了一个分段错误,这似乎是因为该main函数在两个线程完成其工作之前已退出,因此字符缓冲区不是可用了。但是,当我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;
}
If that is the case, how could I handle the case where plenty of identical threads (like in the code below) would be created using the same thread identifier? In that case, how can I make sure that all the threads will have finished before mainexits? Do I really have to keep an array of NUM_STUDENTS pthread_tidentifiers to be able to do this? I guess I could do this by letting the Student threads signal a semaphore and then let the mainfunction wait on that semaphore, but is there really no easier way to do this?
如果是这种情况,我如何处理使用相同线程标识符创建大量相同线程(如下面的代码)的情况?在这种情况下,如何确保所有线程在main退出之前都已完成?我真的必须保留一组NUM_STUDENTS pthread_t标识符才能做到这一点吗?我想我可以通过让学生线程发出信号量信号然后让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);
}
回答by Amardeep AC9MF
pthread_exit()is a function called by a thread to terminate its own execution. For the situation you've given it is not to be called from your main program thread.
pthread_exit()是一个由线程调用以终止其自身执行的函数。对于您给出的情况,不会从主程序线程中调用它。
As you have figured out, pthread_join()is the correct means to wait for the completion of a joinable thread from main().
正如您所发现的,pthread_join()等待可连接线程从main().
Also as you've figured out, you need to maintain the value returned from pthread_create()to pass to pthread_join().
此外,正如您所发现的,您需要维护从pthread_create()传递给 的返回值pthread_join()。
What this means is that you cannot use the same pthread_tvariable for all the threads you create if you intend to use pthread_join().
这意味着pthread_t如果您打算使用pthread_join().
Rather, build an array of pthread_tso that you have a copy of each thread's ID.
相反,构建一个数组,pthread_t以便您拥有每个线程 ID 的副本。
回答by Steve Jessop
Quite aside from whether the program should or should not terminate when the main thread calls pthread_exit, pthread_exitsays
除了在主线程调用时程序是否应该终止之外pthread_exit,pthread_exit还说
The pthread_exit() function terminates the calling thread
pthread_exit() 函数终止调用线程
And also:
并且:
After a thread has terminated, the result of access to local (auto) variables of the thread is undefined.
线程终止后,访问线程的本地(自动)变量的结果是未定义的。
Since the context is an automatic variable of main(), your code can fall over before it even gets to the point of testing what you want it to test...
由于上下文是 的自动变量main(),因此您的代码甚至可能在到达测试您希望它测试的内容之前就失败......
回答by Jonathan Leffler
A mini saga
一个迷你传奇
You don't mention the environment in which you are running the original code. I modified your code to use nanosleep()(since, as I mentioned in a comment to the question, sleep()takes an integer and therefore sleep(0.2)is equivalent to sleep(0)), and compiled the program on MacOS X 10.6.4.
您没有提到运行原始代码的环境。我修改了您的代码以使用nanosleep()(因为,正如我在对问题的评论中提到的,sleep()采用整数,因此sleep(0.2)等效于sleep(0)),并在 MacOS X 10.6.4 上编译了该程序。
Without error checking
没有错误检查
It works fine; it took about 100 seconds to run with the 0.5 probability factor (as you'd expect; I changed that to 0.05 to reduce the runtime to about 10 seconds), and generated a random string - some of the time.
它工作正常;以 0.5 的概率因子运行大约需要 100 秒(正如您所期望的;我将其更改为 0.05 以将运行时间减少到大约 10 秒),并生成了一个随机字符串 - 有些时候。
Sometimes I got nothing, sometimes I got more and sometimes I got less data. But I didn't see a core dump (not even with 'ulimit -c unlimited' to allow arbitrarily large core dumps).
有时我什么也没得到,有时我得到更多,有时我得到的数据更少。但是我没有看到核心转储(甚至没有使用 'ulimit -c unlimited' 来允许任意大的核心转储)。
Eventually, I applied some tools and got to see that I always got 1025 characters (1024 generated plus a newline), but quite often, I got 1024 ASCII NUL characters. Sometimes they'd appear in the middle, sometimes at the beginning, etc:
最终,我应用了一些工具,发现我总是得到 1025 个字符(生成的 1024 个加上一个换行符),但很多时候,我得到 1024 个 ASCII NUL 字符。有时它们会出现在中间,有时会出现在开头,等等:
$ ./pth | tpipe -s "vis | ww -w64" "wc -c"
1025
sem_init(&context.full) failed (-1)
errno = 78 (Function not implemented)
0/*
cat pthread_exit.c (sample code to test pthread_exit() in main())
source:
"pthreads in C - pthread_exit",
http://stackoverflow.com/questions/3330048/pthreads-in-c-pthread-exit
compiled on Mac OS X 10.6.8 with:
gcc -ansi -pedantic -std=gnu99 -Os -Wall -Wextra -Wshadow -Wpointer-arith -Wcast-qual -Wstrict-prototypes \
-Wmissing-prototypes -Wformat=2 -l pthread -o pthread_exit pthread_exit.c
test with:
time -p bash -c './pthread_exit | tee >(od -c 1>&2) | wc -c'
*/
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <assert.h>
#include <semaphore.h>
#include <time.h>
void *Reader(void* arg);
void *Writer(void* arg);
// #define NUM_CHAR 1024
#define NUM_CHAR 100
#define BUFFER_SIZE 8
typedef struct {
pthread_mutex_t mutex;
sem_t *full;
sem_t *empty;
const char *semname1;
const char *semname2;
char* buffer;
} Context;
static char buffer[BUFFER_SIZE];
static Context context;
void *Reader(void* arg) {
Context *contextr = (Context*) arg;
for (int i = 0; i < NUM_CHAR; ++i) {
sem_wait(contextr->full);
pthread_mutex_lock(&(contextr->mutex));
char c = contextr->buffer[i % BUFFER_SIZE];
pthread_mutex_unlock(&(contextr->mutex));
sem_post(contextr->empty);
printf("%c", c);
}
printf("\n");
return NULL;
}
void *Writer(void* arg) {
Context *contextw = (Context*) arg;
for (int i = 0; i < NUM_CHAR; ++i) {
sem_wait(contextw->empty);
pthread_mutex_lock(&(contextw->mutex));
contextw->buffer[i % BUFFER_SIZE] = 'a' + (rand() % 26);
float ranFloat = (float) rand() / RAND_MAX;
//if (ranFloat < 0.5) sleep(0.2);
if (ranFloat < 0.5)
nanosleep((struct timespec[]){{0, 200000000L}}, NULL);
pthread_mutex_unlock(&(contextw->mutex));
sem_post(contextw->full);
}
return NULL;
}
int main(void) {
pthread_t reader, writer;
srand(time(NULL));
int status = 0;
status = pthread_mutex_init(&context.mutex, NULL);
context.semname1 = "Semaphore1";
context.semname2 = "Semaphore2";
context.full = sem_open(context.semname1, O_CREAT, 0777, 0);
if (context.full == SEM_FAILED)
{
fprintf(stderr, "%s\n", "ERROR creating semaphore semname1");
exit(EXIT_FAILURE);
}
context.empty = sem_open(context.semname2, O_CREAT, 0777, BUFFER_SIZE);
if (context.empty == SEM_FAILED)
{
fprintf(stderr, "%s\n", "ERROR creating semaphore semname2");
exit(EXIT_FAILURE);
}
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
sem_unlink(context.semname1);
sem_unlink(context.semname2);
pthread_exit(NULL);
return 0;
}
0Be conservative in what you send; be liberal in what you accept.
0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0
##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0
##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0
##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0
##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0
##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0
##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0
##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0
##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0
##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0
##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0
##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0
##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0
##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0
##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0
##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0
##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0
##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0
##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0
##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0##代码##0ocriexffwgdvdvyfitjtvlzcoffhusjo
zyacniffpsfswesgrkuxycsubufamxxzkrkqnwvsxcbmktodessyohixsmuhdovt
hhertqjjinzoptcuqzertybicrzaeyqlyublbfgutcdvftwkuvxhouiuduoqrftw
xjkgqutpryelzuaerpsbotwyskaflwofseibfqntecyseufqxvzikcyeeikjzsye
qxhjwrjmunntjwhohqovpwcktolcwrvmfvdfsmkvkrptjvslivbfjqpwgvroafzn
fkjumqxjbarelbrdijfrjbtiwnajeqgnobjbksulvcobjkzwwifpvpmpwyzpwiyi
cdpwalenxmocmtdluzouqemmjdktjtvfqwbityzmronwvulfizpizkiuzapftxay
obwsfajcicvcrrjehjeyzsngrwusbejiovaaatyzouktetcerqxjsdpswixjpege
blxscdebfsptxwvwsllvydipovzmnrvoiopmqotydqaujwdykidmwzitdsropguv
vudyfiaaaqueyllnwudfpplcfbsngqqeyucdawqxqzczuwsnaquofreilzvdwbjq
ksrouwltvaktpdrvjnqahpdqdshmmvntspglexggshqbjrvxceaqlfnukedxzlms
cnapdtgtcoyhnglojbjnplowericrzbfulvrobfn
$
(The 'tpipe' program is like 'tee' but it writes to pipes instead of files (and to standard output unless you specify the '-s' option); 'vis' comes from 'The UNIX Programming Environment' by Kernighan & Pike; 'ww' is a 'word wrapper' but there aren't any words here so it brute force wraps at width 64.)
(“tpipe”程序类似于“tee”,但它写入管道而不是文件(以及标准输出,除非您指定“-s”选项);“vis”来自 Kernighan & Pike 的“The UNIX Programming Environment” ; 'ww' 是一个 'word wrapper',但这里没有任何单词,所以它在宽度 64 处强力包装。)
The behaviour I was seeing was highly indeterminate - I'd get different results on each run. I even replaced the random characters with the alphabet in sequence ('a' + i % 26), and was still getting odd behaviour.
我看到的行为是高度不确定的——每次运行我都会得到不同的结果。我什至用字母顺序('a' + i % 26)替换了随机字符,并且仍然出现奇怪的行为。
I added some debug printing code (and a counter to the contex), and it was clear that the semaphore context->fullwas not working properly for the reader - it was being allowed to go into the mutual exclusion before the writer had written anything.
我添加了一些调试打印代码(和上下文的计数器),很明显信号量context->full不能为读者正常工作——在作者写任何东西之前,它被允许进入互斥。
With error checking
带错误检查
When I added error checking to the mutex and semaphore operations, I found that:
当我在互斥量和信号量操作中添加错误检查时,我发现:
##代码##So, the weird outputs are because MacOS X does not implement sem_init(). It's odd; the sem_wait()function failed with errno = 9 (EBADF 'Bad file descriptor'); I added the checks there first. Then I checked the initialization...
所以,奇怪的输出是因为 MacOS X 没有实现sem_init(). 这很奇怪; 在sem_wait()与错误号= 9(EBADF“坏文件描述符”)失败功能; 我首先在那里添加了支票。然后我检查了初始化...
Using sem_open() instead of sem_init()
使用 sem_open() 而不是 sem_init()
The sem_open()calls succeed, which looks good (names "/full.sem"and "/empty.sem", flags O_CREAT, mode values of 0444, 0600, 0700 at different times, and initial values 0 and BUFFER_SIZE, as with sem_init()). Unfortunately, the first sem_wait()or sem_post()operation fails with errno = 9 (EBADF 'Bad file descriptor') again.
该sem_open()呼叫成功,这看起来很不错(名称"/full.sem"和"/empty.sem",标志O_CREAT,在不同时期的0444,0600,0700模式值和初始值0,BUFFER_SIZE,与sem_init())。不幸的是,第一个sem_wait()orsem_post()操作再次失败,errno = 9(EBADF 'Bad file descriptor')。
Morals
德
- It is important to check error conditions from system calls.
- The output I see is non-deterministic because the semaphores don't work.
- That doesn't alter the 'it does not crash without the
pthread_join()calls' behaviour. - MacOS X does not have a working POSIX semaphore implementation.
- 从系统调用中检查错误情况很重要。
- 我看到的输出是不确定的,因为信号量不起作用。
- 这不会改变“没有
pthread_join()调用就不会崩溃”的行为。 - MacOS X 没有有效的 POSIX 信号量实现。
回答by m1tk4
pthread_join()is the standard way to wait for the other thread to complete, I would stick to that.
pthread_join()是等待另一个线程完成的标准方法,我会坚持下去。
Alternatively, you can create a thread counter and have all child threads increment it by 1 at start, then decrement it by 1 when they finish (with proper locking of course), then have your main()wait for this counter to hit 0. (pthread_cond_wait()would be my choice).
或者,您可以创建一个线程计数器并让所有子线程在开始时将其递增 1,然后在它们完成时将其递减 1(当然有适当的锁定),然后main()等待此计数器达到 0。(pthread_cond_wait()将是我的选择)。
回答by chad
There is no need for calling pthread_join(reader,NULL);at all if Contextand bufferare declared with static storage duration (as already pointed out by Steve Jessop, caf and David Schwartz).
pthread_join(reader,NULL);如果Context和buffer声明为静态存储持续时间,则根本不需要调用(正如 Steve Jessop、caf 和 David Schwartz 已经指出的那样)。
Declaring Contextand bufferstatic also makes it necessary to change Context *contextto Context *contextror Context *contextwrespectively.
声明Context和buffer静态也使得有必要分别更改Context *context为Context *contextr或Context *contextw。
In addition, the following rewrite called pthread_exit.creplaces sem_init()with sem_open()and uses nanosleep()(as suggested by Jonathan Leffler).
此外,下面的rewrite称为pthread_exit.c内容替换sem_init()与sem_open()和用途nanosleep()(由乔纳森·莱弗勒的建议)。
pthread_exitwas tested on Mac OS X 10.6.8 and did not output any ASCII NUL characters.
pthread_exit在 Mac OS X 10.6.8 上测试过,没有输出任何 ASCII NUL 字符。
回答by David Schwartz
When you pass a thread a pointer to a variable, you need to ensure that the lifetime of that variable is at least as long as the thread will attempt to access that variable. You pass the threads pointers to bufferand context, which are allocated on the stack inside main. As soon as mainexits, those variables cease to exist. So you cannot exit from mainuntil you confirm that those threads no longer need access to those pointers.
当您向线程传递一个指向变量的指针时,您需要确保该变量的生命周期至少与线程尝试访问该变量的时间一样长。您将线程指针传递给buffer和context,它们在内部的堆栈上分配main。一旦main退出,这些变量就不再存在。因此,main在您确认这些线程不再需要访问这些指针之前,您无法退出。
95% of the time, the fix for this problem is to follow this simple pattern:
95% 的情况下,解决此问题的方法是遵循以下简单模式:
1) Allocate an object to hold the parameters.
2) Fill in the object with the parameters.
3) Pass a pointer to the object to the new thread.
4) Allow the new thread to deallocate the object.
1)分配一个对象来保存参数。
2) 用参数填充对象。
3) 将指向对象的指针传递给新线程。
4) 允许新线程释放对象。
Sadly, this doesn't work well for objects shared by two or more threads. In that case, you can put a use count and a mutex inside the parameter object. Each thread can decrement the use count under protection of the mutex when it's done. The thread that drops the use count to zero frees the object.
遗憾的是,这对于由两个或多个线程共享的对象效果不佳。在这种情况下,您可以在参数对象中放置一个使用计数和一个互斥锁。完成后,每个线程都可以在互斥锁的保护下减少使用计数。将使用计数降至零的线程将释放对象。
You would need to do this for both bufferand context. Set the use count to 2and then pass a pointer to this object to both threads.
您将需要两个这样做buffer和context。将使用计数设置为2,然后将指向此对象的指针传递给两个线程。
回答by Praveen S
pthread_joindoes the following :
pthread_join执行以下操作:
The
pthread_join()function suspends execution of the calling thread until the target thread terminates, unless the target thread has already terminated. On return from a successfulpthread_join()call with a non-NULLvalue_ptrargument, the value passed topthread_exit()by the terminating thread is made available in the location referenced byvalue_ptr. When apthread_join()returns successfully, the target thread has been terminated. The results of multiple simultaneous calls topthread_join()specifying the same target thread are undefined. If the thread callingpthread_join()is canceled, then the target thread will not be detached.
该
pthread_join()函数会暂停调用线程的执行,直到目标线程终止,除非目标线程已经终止。从pthread_join()带有非 NULLvalue_ptr参数的成功调用返回时,pthread_exit()终止线程传递给的值在 引用的位置中可用value_ptr。当 apthread_join()成功返回时,目标线程已被终止。多个同时调用pthread_join()指定同一个目标线程的结果是不确定的。如果线程调用pthread_join()被取消,那么目标线程将不会被分离。
However you can achieve the same by using a light weight loop which will prevent the exefrom exiting. In Glib this is achieved by creating a GMainLoop, in Gtk+ you can use the gtk_main.
After completion of threads you have to quit the main loop or call gtk_exit.
但是,您可以通过使用轻量级循环来防止exe退出。在 Glib 中,这是通过创建GMainLoop来实现的,在 Gtk+ 中,您可以使用gtk_main。线程完成后,您必须退出主循环或调用gtk_exit.
Alternatively you can create you own wait functionality using a combination of sockets,pipes and select system call but this is not required and can be considered as an exercise for practice.
或者,您可以使用套接字、管道和选择系统调用的组合来创建自己的等待功能,但这不是必需的,可以将其视为练习练习。
回答by Alex Martelli
Per normal pthreadsemantics, as taught e.g. here, your original idea does seem to be confirmed:
按照正常的pthread语义,例如教这里,你最初的想法似乎得到证实:
If main() finishes before the threads it has created, and exits with pthread_exit(), the other threads will continue to execute. Otherwise, they will be automatically terminated when main() finishes.
如果 main() 在它创建的线程之前完成,并使用 pthread_exit() 退出,则其他线程将继续执行。否则,它们将在 main() 完成时自动终止。
However I'm not sure whether that's part of the POSIX threads standardor just a common but not universal "nice to have" add-on tidbit (I do know that some implementations don't respect this constraint -- I just don't know whether those implementations are nevertheless to be considered standard compliant!-). So I'll have to join the prudent chorus recommending the joining of every thread you need to terminate, just to be on the safe side -- or, as Jon Postel put itin the context of TCP/IP implementations:
但是,我不确定这是否是 POSIX 线程标准的一部分,还是只是一个常见但不通用的“好用”附加花絮(我确实知道某些实现不遵守此约束——我只是不知道这些实现是否仍被视为符合标准!-)。所以我必须加入谨慎的合唱团,建议加入您需要终止的每个线程,只是为了安全起见——或者,正如 Jon Postel在 TCP/IP 实现的上下文中所说的那样:
##代码##a "principle of robustness" that should be used way more broadly than just in TCP/IP;-).
一种“健壮性原则”,应该比仅在 TCP/IP 中使用更广泛;-)。
回答by Nikolai Fetissov
pthread_exit(3)exits the thread that calls it (but not the whole process if other threads are still running). In your example other threads use variables on main's stack, thus when main's thread exits and its stack is destroyed they access unmapped memory, thus the segfault.
pthread_exit(3)退出调用它的线程(但如果其他线程仍在运行,则不会退出整个进程)。在您的示例中,其他线程使用main's 堆栈上的变量,因此当main's 线程退出并且其堆栈被破坏时,它们访问未映射的内存,从而导致段错误。
Use proper pthread_join(3)technique as suggested by others, or move shared variables into static storage.
pthread_join(3)按照其他人的建议使用适当的技术,或将共享变量移动到静态存储中。

