《第11章 线程》
1.线程创建
#include <pthread.h> int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg ); 返回值:成功:0; 失败:返回错误编号
参数:
tidp:新创建线程的线程ID会被设置成tidp指向的内润单元;
attr:用于定制各种不同的线程属性,不用的时候设置为NULL,创建一个具有默认属性的线程;
start_rtn:新创建的线程从start_rtn函数的地址开始运行;
arg:如果start_rtn函数传递的参数有一个以上,那么需要把这些参数放在一个结构中,然后把这个结构的地址作为arg参数传入;
线程创建时,并不能保证哪个线程会先运行。
SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。#include <pthread.h> pthread_t ntid; void printfs(const char *s) { pid_t pid; pthread_t tid; pid = getpid(); tid = pthread_self(); //获取当前线程的ID printf("%s pid %lu tid %lu (0x%1x) \n", s,(unsigned long) pid, (unsigned long)tid, (unsigned long)tid); } void *thr_fn(void *arg) { printfs("new thread:"); return((void *) 0); } int main(void) { int err; err = pthread_create(&ntid, NULL, thr_fn, NULL); if(err != 0) err_exit(err, "can't create thread"); printfs("main thread:"); sleep(1); exit(0); }
以上例程有两个需要注意的点:
- 需要特别注意主线程和新线程的竞争(线程创建时,并不能保证哪个线程会先运行),所以目前这里采用的主线程休眠一秒,如果主线程不休眠,并且是主线程先运行,那么久会直接exit,新线程就没有运行的机会。
- 新线程是通过pthread_self来获取自己的线程ID。而不是通过ntid。因为主线程通过pthread_create创建新线程,会把新线程的ID存在放第一个参数也就是ntid上。但是新建的线程并不能安全的使用它。理由是:如果新线程在主线程调用pthread_create返回之前就运行了。那么新线程看到的是未初始化的ntid内容,这个内容并不是正确的线程ID。
导致以上两个特别需要注意的原因都是线程创建时,并不能保证哪个线程会先运行。
2.线程终止
如果进程中的任意线程调用了exit、_Exit或者_exit,那么整个进程就会终止。
单个线程在不终止整个进程的情况下可以通过三种方式退出:
- 线程可以简单地从启动例程中返回(函数运行结束退出),返回值是线程的退出码(return)。
- 线程可以被同一进程中的其他线程取消。
- 线程调用pthread_exit。
#include <pthread.h> void pthread_exit(void *rval_ptr); rval_ptr参数是一个无类型指针,就是一个返回值。进程中的其他线程也可以通过调用pthread_join函数访问到这个指针。
int pthread_join(pthread_t thread, void **rval_ptr);
返回值: 成功:0; 失败:返回错误编号
调用线程将一直阻塞,直到指定的线程调用pthread_exit、从启动例程中返回或者被取消。
如果线程简单地从它的启动例程返回,pval_ptr就包含返回码。如果线程被取消,由rval_ptr指定的内存单元就设置为PTHREAD_CANCELED.
可以通过调用pthread_join自动把线程置于分离一个状态,这样资源就可以恢复。如果线程已经处于分离状态,pthread_join调用就会失败,返回einval。
可以看到,当一个线程通过调用pthread_exit退出或者简单从启动例程中返回时,进程中的其他线程可以通过使用pthread_join函数获得该线程的退出状态。
pthread_create和pthrad_exit函数的无类型指针参数可以传递的值不止一个,这个指针可以传递包含复杂信息的结构的地址。但是注意,这个结构所使用的内存在调用者完成调用以后必须仍然有效。例如:在调用线程的栈上分配了该结构,那么其他的线程在使用这个结果的时候内存内容可能已经改变了。又比如:线程在自己的栈上分配了一个结构,然后把指向这个结构的指针传给pthread_exit,那么调用pthread_join的线程试图使用该结构时,这个栈有可能已经被撤销。

更多精彩