线程终止
以下内容翻译的是:
http://man7.org/linux/man-pages/man3/pthread_create.3.html
The new thread terminates in one of the following ways: * It calls pthread_exit(3), specifying an exit status value that is available to another thread in the same process that calls pthread_join(3). * It returns from start_routine(). This is equivalent to calling pthread_exit(3) with the value supplied in the return statement. * It is canceled (see pthread_cancel(3)). * Any of the threads in the process calls exit(3), or the main thread performs a return from main(). This causes the termination of all threads in the process.
片段。 线程中断有以下几种方式:
线程中调用thread exit函数,该函数调用需要指定一个退出状态,如果有其他线程 thread join这个线程的话,这个状态值有用。
线程函数返回。这种方式等同于thread exit,exit的状态值等同于返回值。
调用thread cancel, 请求取消了这个线程。
在程序中任何地方、任何线程中调用了exit方法退出,包括在主线程main方法返回都将 中断所有线程。
请求取消线程
可以通过pthread_cancel函数请求取消线程。pthread_cancel函数会发送一个cancel请求给被取消线程。
另一个相关函数
pthread_testcancel
void pthread_testcancel(void);
请求投递pending状态的cancel请求。如果请求队列中有cancel请求的话,该函数请求将cancel请求投递给被取消线程。如果请求队列中没有cancel请求, 调用该函数无影响。
另外,该函数将在线程中创建一个取消点(Cancellation points),这样的话,如果一个线程除了其他执行代码之外没有取消点(Cancellation points),将响应cancel请求。
被取消线程是否会响应pthread_cancel的cancel请求取决于被取消线程的两个控制属性(可撤销属性):state、type。state表示线程的可撤销状态,type表示线程的可撤销类型。
state可以是enabled (新创建的线程默认为enabled,表示可撤销)或者disabled。
不管state设置为enabled 还是disabled,都是调用pthread_cancel向线程发起cancel请求,如果disabled,发起的cancel请求将会保留在请求队列中,直到enabled可撤销状态state。
type可以是asynchronous或者deferred (新创建的线程默认为deferred)。如果type设置为asynchronous,表示取消操作是异步的,取消操作可能在任何时候被取消,通常会立即取消,但系统并不保证会立即取消,值得注意的是系统有时候还不保证最后就一定能取消成功。如果type设置为deferred,取消操作将延迟到被取消线程下次调用一个可以作为取消点(Cancellation points)的函数的时候。
可以作为取消点(Cancellation points)的函数列表:
参考http://man7.org/linux/man-pages/man7/pthreads.7.html
Cancellation points POSIX.1 specifies that certain functions must, and certain other functions may, be cancellation points. If a thread is cancelable, its cancelability type is deferred, and a cancellation request is pending for the thread, then the thread is canceled when it calls a function that is a cancellation point. The following functions are required to be cancellation points by POSIX.1-2001 and/or POSIX.1-2008: accept() aio_suspend() clock_nanosleep() close() connect() creat() fcntl() F_SETLKW fdatasync() fsync() getmsg() getpmsg() lockf() F_LOCK mq_receive() mq_send() mq_timedreceive() mq_timedsend() msgrcv() msgsnd() msync() nanosleep() open() openat() [Added in POSIX.1-2008] pause() poll() pread() pselect() pthread_cond_timedwait() pthread_cond_wait() pthread_join() pthread_testcancel() putmsg() putpmsg() pwrite() read() readv() recv() recvfrom() recvmsg() select() sem_timedwait() sem_wait() send() sendmsg() sendto() sigpause() [POSIX.1-2001 only (moves to "may" list in POSIX.1-2008)] sigsuspend() sigtimedwait() sigwait() sigwaitinfo() sleep() system() tcdrain() usleep() [POSIX.1-2001 only (function removed in POSIX.1-2008)] wait() waitid() waitpid() write() writev() The following functions may be cancellation points according to POSIX.1-2001 and/or POSIX.1-2008: access() asctime() asctime_r() catclose() catgets() catopen() chmod() [Added in POSIX.1-2008] chown() [Added in POSIX.1-2008] closedir() closelog() ctermid() ctime() ctime_r() dbm_close() dbm_delete() dbm_fetch() dbm_nextkey() dbm_open() dbm_store() dlclose() dlopen() dprintf() [Added in POSIX.1-2008] endgrent() endhostent() endnetent() endprotoent() endpwent() endservent() endutxent() faccessat() [Added in POSIX.1-2008] fchmod() [Added in POSIX.1-2008] fchmodat() [Added in POSIX.1-2008] fchown() [Added in POSIX.1-2008] fchownat() [Added in POSIX.1-2008] fclose() fcntl() (for any value of cmd argument) fflush() fgetc() fgetpos() fgets() fgetwc() fgetws() fmtmsg() fopen() fpathconf() fprintf() fputc() fputs() fputwc() fputws() fread() freopen() fscanf() fseek() fseeko() fsetpos() fstat() fstatat() [Added in POSIX.1-2008] ftell() ftello() ftw() futimens() [Added in POSIX.1-2008] fwprintf() fwrite() fwscanf() getaddrinfo() getc() getc_unlocked() getchar() getchar_unlocked() getcwd() getdate() getdelim() [Added in POSIX.1-2008] getgrent() getgrgid() getgrgid_r() getgrnam() getgrnam_r() gethostbyaddr() [SUSv3 only (function removed in POSIX.1-2008)] gethostbyname() [SUSv3 only (function removed in POSIX.1-2008)] gethostent() gethostid() gethostname() getline() [Added in POSIX.1-2008] getlogin() getlogin_r() getnameinfo() getnetbyaddr() getnetbyname() getnetent() getopt() (if opterr is nonzero) getprotobyname() getprotobynumber() getprotoent() getpwent() getpwnam() getpwnam_r() getpwuid() getpwuid_r() gets() getservbyname() getservbyport() getservent() getutxent() getutxid() getutxline() getwc() getwchar() getwd() [SUSv3 only (function removed in POSIX.1-2008)] glob() iconv_close() iconv_open() ioctl() link() linkat() [Added in POSIX.1-2008] lio_listio() [Added in POSIX.1-2008] localtime() localtime_r() lockf() [Added in POSIX.1-2008] lseek() lstat() mkdir() [Added in POSIX.1-2008] mkdirat() [Added in POSIX.1-2008] mkdtemp() [Added in POSIX.1-2008] mkfifo() [Added in POSIX.1-2008] mkfifoat() [Added in POSIX.1-2008] mknod() [Added in POSIX.1-2008] mknodat() [Added in POSIX.1-2008] mkstemp() mktime() nftw() opendir() openlog() pathconf() pclose() perror() popen() posix_fadvise() posix_fallocate() posix_madvise() posix_openpt() posix_spawn() posix_spawnp() posix_trace_clear() posix_trace_close() posix_trace_create() posix_trace_create_withlog() posix_trace_eventtypelist_getnext_id() posix_trace_eventtypelist_rewind() posix_trace_flush() posix_trace_get_attr() posix_trace_get_filter() posix_trace_get_status() posix_trace_getnext_event() posix_trace_open() posix_trace_rewind() posix_trace_set_filter() posix_trace_shutdown() posix_trace_timedgetnext_event() posix_typed_mem_open() printf() psiginfo() [Added in POSIX.1-2008] psignal() [Added in POSIX.1-2008] pthread_rwlock_rdlock() pthread_rwlock_timedrdlock() pthread_rwlock_timedwrlock() pthread_rwlock_wrlock() putc() putc_unlocked() putchar() putchar_unlocked() puts() pututxline() putwc() putwchar() readdir() readdir_r() readlink() [Added in POSIX.1-2008] readlinkat() [Added in POSIX.1-2008] remove() rename() renameat() [Added in POSIX.1-2008] rewind() rewinddir() scandir() [Added in POSIX.1-2008] scanf() seekdir() semop() setgrent() sethostent() setnetent() setprotoent() setpwent() setservent() setutxent() sigpause() [Added in POSIX.1-2008] stat() strerror() strerror_r() strftime() symlink() symlinkat() [Added in POSIX.1-2008] sync() syslog() tmpfile() tmpnam() ttyname() ttyname_r() tzset() ungetc() ungetwc() unlink() unlinkat() [Added in POSIX.1-2008] utime() [Added in POSIX.1-2008] utimensat() [Added in POSIX.1-2008] utimes() [Added in POSIX.1-2008] vdprintf() [Added in POSIX.1-2008] vfprintf() vfwprintf() vprintf() vwprintf() wcsftime() wordexp() wprintf() wscanf() An implementation may also mark other functions not specified in the standard as cancellation points. In particular, an implementation is likely to mark any nonstandard function that may block as a cancella‐ tion point. (This includes most functions that can touch files.)
这两个属性可分别通过pthread_setcancelstate和pthread_setcanceltype函数设置。
int oldstate; pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); printf("pre cancel state %d\n", oldstate);
如果设置为PTHREAD_CANCEL_ENABLE,表示enabled,如果设置为PTHREAD_CANCEL_DISABLE,表示disabled。
int oldtype; pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldtype); printf("pre cancel type %d\n", oldtype);
如果设置为PTHREAD_CANCEL_DEFERRED,表示deferred ,如果设置为PTHREAD_CANCEL_ASYNCHRONOUS,表示asynchronous。
线程的这两个控制属性(可撤销属性):state、type默认分别为:PTHREAD_CANCEL_ENABLE、PTHREAD_CANCEL_DEFERRED。
第一种情况:通过pthread_exit函数终止线程执行。
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> int *exitStatus = NULL; int count = 0; void* run_up(void *arg) { printf("&exitStatus: %d, exitStatus: %d, *exitStatus: %d, &*exitStatus: %d\n", &exitStatus, exitStatus, *exitStatus, &*exitStatus); pthread_exit((void *) exitStatus); //pthread_exit(NULL); //const char *s = "Thread funtion finished!"; //pthread_exit((void *) s); //return (void *) exitStatus; //return NULL; //return (void *) "Thread funtion finished!"; } int main() { exitStatus = (int *) malloc(sizeof(int)); *exitStatus = 8; pthread_t pthread1, pthread2; pthread_create(&pthread1, NULL, run_up, (void *) 0); int *p_status = (int *) malloc(sizeof(int)); int **status = &p_status; pthread_join(pthread1, (void **) status); printf("&p_status: %d, p_status: %d, *p_status: %d, &*p_status: %d\n", &p_status, p_status, *p_status, &*p_status); printf("&status: %d, status: %d, *status: %d, &*status: %d, **status: %d, &**status: %d\n", &status, status, *status, &*status, **status, &**status); printf("final count: %d\n", count); return 0; }
include_pthread = /cygdrive/d/usr/lib/pthreads-w32-2-8-0-release/Pre-built.2/include lib_pthread = /cygdrive/d/usr/lib/pthreads-w32-2-8-0-release/Pre-built.2/lib OUTPUT = ../Debug/ objs = $(OUTPUT)*.o make: make-std make-nostd: clean g++ -c pthread_exit_test2.cpp -o ../Debug/pthread_exit_test2.o # -L$(lib_pthread) 指定lib库文件的位置:-L/cygdrive/d/usr/lib/pthreads-w32-2-8-0-release/Pre-built.2/lib # 如果没有指定lib库文件的位置:-L$(lib_pthread),需要将lib库文件拷贝到可以查找到的目录下。我这里是cygwin # 环境: $ cp -rf /cygdrive/d/usr/lib/pthreads-w32-2-8-0-release/Pre-built.2/lib/libpthreadGC2.a /cygdrive/d/sbin/lib # 这样就可以不指定lib库文件的位置: # g++ $(objs) -o $(OUTPUT)pthread_exit_test2 -lpthreadGC2 g++ $(objs) -o $(OUTPUT)pthread_exit_test2 -L$(lib_pthread) -lpthreadGC2 # g++ $(objs) -o $(OUTPUT)pthread_exit_test2 -lpthreadGC2 make-std: clean g++ -c pthread_exit_test2.cpp -o ../Debug/pthread_exit_test2.o g++ $(objs) -o $(OUTPUT)pthread_exit_test2 -lpthread clean: rm -Rf ./*.bak rm -Rf ./*.o rm -Rf ./*.exe rm -Rf ../Debug/*
pthread使用的是win版本:pthreads-w32-2-8-0-release,Pre-built中包含支持linux的pthread库:libpthreadGC2.a、libpthreadGCE2.a
将Pre-built中包含支持linux的pthread库拷贝到cygwin下:/cygdrive/d/sbin/lib
$ cp -rf /cygdrive/d/usr/lib/pthreads-w32-2-8-0-release/Pre-built.2/lib/libpthreadGC2.a /cygdrive/d/sbin/lib/
make
$ make -f pthread_exit_test2.Makefile make
运行
$ ./pthread_exit_test2.exe
运行结果
&exitStatus: 4210712, exitStatus: 536937064, *exitStatus: 8, &*exitStatus: 536937064 &p_status: 2272376, p_status: 536937064, *p_status: 8, &*p_status: 536937064 &status: 2272372, status: 2272376, *status: 536937064, &*status: 2272376, **status: 8, &**status: 536937064
这个结果是正常的。
第二种情况:线程函数返回。
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> int *exitStatus = NULL; void* run_up(void *arg) { printf("&exitStatus: %d, exitStatus: %d, *exitStatus: %d, &*exitStatus: %d\n", &exitStatus, exitStatus, *exitStatus, &*exitStatus); return (void *) exitStatus; //return NULL; //return (void *) "Thread funtion finished!"; } int main() { exitStatus = (int *) malloc(sizeof(int)); *exitStatus = 8; pthread_t pthread1, pthread2; pthread_create(&pthread1, NULL, run_up, (void *) 0); int *p_status = (int *) malloc(sizeof(int)); int **status = &p_status; pthread_join(pthread1, (void **) status); printf("&p_status: %d, p_status: %d, *p_status: %d, &*p_status: %d\n", &p_status, p_status, *p_status, &*p_status); printf("&status: %d, status: %d, *status: %d, &*status: %d, **status: %d, &**status: %d\n", &status, status, *status, &*status, **status, &**status); return 0; }
第三种情况:通过pthread_cancel函数取消线程执行。
线程的可撤销type属性为deferred的例子:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> #include <errno.h> #include <sys/types.h> int *exitStatus = NULL; void* run_up(void *arg) { pid_t pid = getpid(); // pid_t tid = gettid(); // Glibc does not provide a wrapper for this system call; call it using syscall(2). pthread_t tid = pthread_self(); int i = 0; //int oldstate; //int oldtype; printf("pid: %ld, tid: %ld\n", pid, tid); printf("&exitStatus: %d, exitStatus: %d, *exitStatus: %d, &*exitStatus: %d\n", &exitStatus, exitStatus, *exitStatus, &*exitStatus); //pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); //printf("pre cancel state %d\n", oldstate); //pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldtype); //printf("pre cancel type %d\n", oldtype); while(1) { i++; sleep(1); pthread_testcancel(); } return (void *) exitStatus; } int main() { exitStatus = (int *) malloc(sizeof(int)); *exitStatus = 8; pthread_t pthread1, pthread2; int result = pthread_create(&pthread1, NULL, run_up, (void *) 0); if (result) { printf("error: pthread_create, errno: %d\n", result); } printf("pthread: %ld\n", pthread1); printf("try to cancel thread %ld\n", pthread1); pthread_cancel(pthread1); int *p_status = (int *) malloc(sizeof(int)); int **status = &p_status; result = pthread_join(pthread1, (void **) status); if (result) { printf("error: pthread_join, errno: %d\n", result); } if (p_status == NULL) { printf("p_status is null\n"); } else if (p_status == PTHREAD_CANCELED) { printf("thread %ld canceled.\n", pthread1); } else { printf("&p_status: %d, p_status: %d, *p_status: %d, &*p_status: %d\n", &p_status, p_status, *p_status, &*p_status); printf("&status: %d, status: %d, *status: %d, &*status: %d, **status: %d, &**status: %d\n", &status, status, *status, &*status, **status, &**status); } return 0; }
这里要注意的是,线程执行函数run_up中while循环中的sleep(1);pthread_testcancel();函数调用,这两个都是可以作为取消点(Cancellation points)的函数。有这种函数调用,在向线程发起cancel请求后,线程在收到该请求后会延迟到这种函数调用的时候取消线程执行。
线程的可撤销type属性为asynchronous的例子:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> #include <errno.h> #include <sys/types.h> int *exitStatus = NULL; void* run_up(void *arg) { pid_t pid = getpid(); // pid_t tid = gettid(); // Glibc does not provide a wrapper for this system call; call it using syscall(2). pthread_t tid = pthread_self(); int i = 0; //int oldstate; int oldtype; printf("pid: %ld, tid: %ld\n", pid, tid); printf("&exitStatus: %d, exitStatus: %d, *exitStatus: %d, &*exitStatus: %d\n", &exitStatus, exitStatus, *exitStatus, &*exitStatus); //pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); //printf("pre cancel state %d\n", oldstate); //pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldtype); //printf("pre cancel type %d\n", oldtype); pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype); printf("pre cancel type %d\n", oldtype); while(1) { i++; } return (void *) exitStatus; } int main() { exitStatus = (int *) malloc(sizeof(int)); *exitStatus = 8; pthread_t pthread1, pthread2; int result = pthread_create(&pthread1, NULL, run_up, (void *) 0); if (result) { printf("error: pthread_create, errno: %d\n", result); } printf("pthread: %ld\n", pthread1); printf("try to cancel thread %ld\n", pthread1); pthread_cancel(pthread1); int *p_status = (int *) malloc(sizeof(int)); int **status = &p_status; result = pthread_join(pthread1, (void **) status); if (result) { printf("error: pthread_join, errno: %d\n", result); } if (p_status == NULL) { printf("p_status is null\n"); } else if (p_status == PTHREAD_CANCELED) { printf("thread %ld canceled.\n", pthread1); } else { printf("&p_status: %d, p_status: %d, *p_status: %d, &*p_status: %d\n", &p_status, p_status, *p_status, &*p_status); printf("&status: %d, status: %d, *status: %d, &*status: %d, **status: %d, &**status: %d\n", &status, status, *status, &*status, **status, &**status); } return 0; }
这里要注意的是,线程执行函数run_up中while循环中并没有sleep(1);pthread_testcancel();这样的函数调用(可以作为取消点(Cancellation points)的函数)。通常被取消线程是可以取消执行的,但有时候最后也不能保证线程取消成功。
为了保证线程最后可以被取消成功,可以像上面的例子那样尝试调用一个可以作为取消点(Cancellation points)的函数。如像上面那样在循环里边调用sleep(1);pthread_testcancel();
或者在发起cancel请求的时候多尝试几次:
pthread_cancel(pthread1); int tryt = 0; while (tryt < 100) { pthread_cancel(pthread1); sleep(0.1); tryt++; }
pthread w32版本线程终止(pthread_exit)后通过pthread_join获取线程终止返回值的问题
pthread w32版本线程终止(pthread_exit)后的返回值的问题。
通过pthread_exit终止线程的执行,pthread_join等待线程终止返回的值在pthread w32版本和标准pthread不一样。
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> int *exitStatus = NULL; int count = 0; void* run_up(void *arg) { printf("&exitStatus: %d, exitStatus: %d, *exitStatus: %d, &*exitStatus: %d\n", &exitStatus, exitStatus, *exitStatus, &*exitStatus); pthread_exit((void *) exitStatus); //pthread_exit(NULL); //const char *s = "Thread funtion finished!"; //pthread_exit((void *) s); //return (void *) exitStatus; //return NULL; //return (void *) "Thread funtion finished!"; } int main() { exitStatus = (int *) malloc(sizeof(int)); *exitStatus = 8; pthread_t pthread1, pthread2; pthread_create(&pthread1, NULL, run_up, (void *) 0); int *p_status = (int *) malloc(sizeof(int)); int **status = &p_status; pthread_join(pthread1, (void **) status); printf("&p_status: %d, p_status: %d, *p_status: %d, &*p_status: %d\n", &p_status, p_status, *p_status, &*p_status); printf("&status: %d, status: %d, *status: %d, &*status: %d, **status: %d, &**status: %d\n", &status, status, *status, &*status, **status, &**status); printf("final count: %d\n", count); return 0; }
include_pthread = /cygdrive/d/usr/lib/pthreads-w32-2-8-0-release/Pre-built.2/include lib_pthread = /cygdrive/d/usr/lib/pthreads-w32-2-8-0-release/Pre-built.2/lib OUTPUT = ../Debug/ objs = $(OUTPUT)*.o make: make-std make-nostd: clean g++ -c pthread_exit_test2.cpp -o ../Debug/pthread_exit_test2.o # -L$(lib_pthread) 指定lib库文件的位置:-L/cygdrive/d/usr/lib/pthreads-w32-2-8-0-release/Pre-built.2/lib # 如果没有指定lib库文件的位置:-L$(lib_pthread),需要将lib库文件拷贝到可以查找到的目录下。我这里是cygwin # 环境: $ cp -rf /cygdrive/d/usr/lib/pthreads-w32-2-8-0-release/Pre-built.2/lib/libpthreadGC2.a /cygdrive/d/sbin/lib # 这样就可以不指定lib库文件的位置: # g++ $(objs) -o $(OUTPUT)pthread_exit_test2 -lpthreadGC2 g++ $(objs) -o $(OUTPUT)pthread_exit_test2 -L$(lib_pthread) -lpthreadGC2 # g++ $(objs) -o $(OUTPUT)pthread_exit_test2 -lpthreadGC2 make-std: clean g++ -c pthread_exit_test2.cpp -o ../Debug/pthread_exit_test2.o g++ $(objs) -o $(OUTPUT)pthread_exit_test2 -lpthread clean: rm -Rf ./*.bak rm -Rf ./*.o rm -Rf ./*.exe rm -Rf ../Debug/*
pthread使用的是win版本:pthreads-w32-2-8-0-release,Pre-built中包含支持linux的pthread库:libpthreadGC2.a、libpthreadGCE2.a
将Pre-built中包含支持linux的pthread库拷贝到cygwin下:/cygdrive/d/sbin/lib
$ cp -rf /cygdrive/d/usr/lib/pthreads-w32-2-8-0-release/Pre-built.2/lib/libpthreadGC2.a /cygdrive/d/sbin/lib/
make
$ make -f pthread_exit_test2.Makefile make
运行
$ ./pthread_exit_test2.exe
运行结果
&exitStatus: 4210712, exitStatus: 536937064, *exitStatus: 8, &*exitStatus: 536937064 &p_status: 2272376, p_status: 536937064, *p_status: 8, &*p_status: 536937064 &status: 2272372, status: 2272376, *status: 536937064, &*status: 2272376, **status: 8, &**status: 536937064
这个结果是正常的。
但奇怪的是,如果pthread使用的是win版本:pthreads-w32-2-8-0-release
make
$ make -f pthread_exit_test2.Makefile make-nostd
运行
$ ./pthread_exit_test2.exe
运行结果
运行输出:
&p_status: 2272376, p_status: 536937080, *p_status: 0, &*p_status: 536937080 &exitStatus: 4210712, exitStatus: 536937064, *exitStatus: 8, &*exitStatus: 536937064 &status: 2272372, status: 2272376, *status: 536937080, &*status: 2272376, **status: 0, &**status: 536937080
这个结果就不正常了,和预期结果不一致。
有时候还没打印出exitStatus的值:
&p_status: 2272376, p_status: 536937080, *p_status: 0, &*p_status: 536937080 &status: 2272372, status: 2272376, *status: 536937080, &*status: 2272376, **status: 0, &**status: 536937080
这个就奇怪了。
这个问题后来看了下,发现pthread_join函数调用失败,返回错误:error: errno: 3
根据errno.h中的定义:
#define ESRCH 3 /* No such process */
No thread with the ID thread could be found.
意思是没找到这个线程?
所以这里pthread_join调用后并没有获取到线程终止后的返回值,并没有将线程终止后的返回值拷贝到pthread_join的第二个参数。
只是我在线程函数中可以打印出线程id, 而且和printf("pthread: %ld\n", pthread1);打印出来的值是一致的,而且线程函数也执行了,怎么就找不到这个线程呢?
pid_t pid = getpid(); // pid_t tid = gettid(); // Glibc does not provide a wrapper for this system call; call it using syscall(2). pthread_t tid = pthread_self(); printf("pid: %ld, tid: %ld\n", pid, tid);
那么这个pthread_join调用失败具体是什么原因?
关于线程执行返回值,线程执行终止返回有4中方式,可以通过pthread_join函数得到线程终止时的返回值,前提是对应的线程是joinable的(线程可以是joinable或者detached的)。参考文章:https://lobin.iteye.com/blog/2040285