POSIXThreads
一、 需要掌握的知识点
n在一个进程里面创建新线程
n线程之间在进程里面进行同步数据访问
n对一个线程的属性进行修改
n在线程里面控制另一个同进程里面的线程
二、概念
由于同一进程的多个线程共享同一地址空间,因此Text Segment、Data Segment都是共享的,如果定义一个函数,在各线程中都可以调用,如果定义一个全局变量,在各线程中都可以访问到,除此之外,各线程还共享以下进程资源和环境:
· 文件描述符表
· 每种信号的处理方式(SIG_IGN
、SIG_DFL
或者自定义的信号处理函数)
· 当前工作目录
· 用户id和组id
但有些资源是每个线程各有一份的:
· 线程id
· 上下文,包括各种寄存器的值、程序计数器和栈指针
· 栈空间
· errno
变量
· 信号屏蔽字
· 调度优先级
三、线程的优缺点
Ø 优点:
1. 创建一个新线程的总开支明显比创建一个新进程的要小得多(尽管linux在创建新进程方面特别高效)
2. 如果想让一个程序似乎在同时做两件事,线程是非常有用的。
For example:当一个实时计数字数的文档还在编辑内容期间,我们可以使用一个线程来管理用户的输入和执行编辑,另一个线程可以观察同个文档内容,连续不断的更新字数计数变量,这样第一个线程就能实时保持分享这个变量给用户。
3. 当一个应用程序通过运行3个线程来操作输入,计算,输出的时候,性能上明显改进了。
For example:当输入或者输出线程正在等待一个连接的时候,另一个线程可以继续运行它的计算。
4.现在多芯处理器是常见的,即使在桌面和笔记本电脑的机器,在一个进程里面使用多线程,如果应有程序合适的话,能够让进程更好的利用硬件资源。
5.通常,在线程间进行转换要求操作系统所需要做的事比在进程间进行转换要少得多,所以多线程在资源的要求比多进程低得多。
Ø 缺点
1)线程的死锁。即较长时间的等待或资源竞争以及死锁等多线程症状。
2)对公有变量的同时读或写。当多个线程需要对公有变量进行写操作时,后一个线程往往会修改掉前一个线程存放的数据,从而使前一个线程的参数被修改;另外 ,当公用变量的读写操作是非原子性时,在不同的机器上,中断时间的不确定性,会导致数据在一个线程内的操作产生错误,从而产生莫名其妙的错误,而这种错误是程序员无法预知的。
四、如果在程序中要使用线程,就必须定义一个宏_REENTRANT,再包含进头文件pthread.h,链接上线程库通过使用-lpthread.
五、创建一个新的线程
#include<pthread.h>
intpthread_create(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void*), void *arg);
thread:指向一个pthread_t结构类型,当一个线程被创建时,一个标识符会被写入一个存储单元,这个单元的地址会被写入thread,这个标识符可以让你了解这个thread。
Attr:指向pthread_attr_t结构类型,这个结构类型可以用来设置线程的属性,如果不需要设置特别的属性时,可以使用NULL。
Start_routine:这个函数指针用来告知新创建的线程要开始执行的函数,其中的参数是由arg传入。
Arg:作为参数传入到start_routine。
返回值:0时成功,或者一个错误值用来标志错误。
六、线程的退出
当一个线程终止的时候,他调用pthread_exit函数,类似于进程结束调用exit函数一样。使得函数可以在结束后返回一个指针指向某个对象,这个对象不能是一个局部变量。
#include<pthread.h>
void pthread_exit(void*retval);
pthread_join函数的角色就好比进程里面的wait函数用于收集子进程一样。
int pthread_join(pthread_tth, void **thread_return);
th:这个参数是用于标识所wait的线程,传递给这个参数的pthread_t结构在pthread_creat的时候就被写入了,所以供你使用。
Thread_return:这个参数是用来存放一个指向无符号型的指针的指针。当线程pthread_exit后所返回的信息的指针就会被存放到这个参数所指向的位置。
返回值:0时成功,错误时为错误码。
Ø 以下是一个简单的例子
u 在编译的过程中要确定_REENTRANT被定义了,在少数的一些系统,你还必须定义_POSIX_C_SOURCE。但通常是不需要的。
u 你还必须确定适当的线程库被链接上。
$ cc -D_REENTRANT -I/usr/include/nptlthread1.c
–o thread1 -L/usr/lib/nptl -lpthread
If NPTL is the default on your system(which is quite likely), you almost certainly don’t need the –I and
–L options, and can use the simpler:
$ cc -D_REENTRANTthread1.c –o thread1 -lpthread
Wewill use the simpler version of the compile line throughout this chapter.
u 运行结果如下
$ ./thread1
Waiting for thread to finish...
thread_function is running. Argument was HelloWorld
Thread joined, it returned Thank you forthe CPU time
Messageis now Bye!
这里如果使用fork代替pthread_create,那么message数组就会被copy出一份给子进程了,而不像线程那样共享message数组。