使用线程的好处?
- 异步变同步——在处理异步事件时,指定一个单独的线程(thread)去处理不同类型的事件,每个线程可以使用同步编程模型去处理它自己的事件,而同步模型要比异步简单很多。
- 共享内存和文件描述符——在多进程情况下,操作系统必须提供复杂机制用来在进程间共享内存(memory)和文件描述符(file descriptors)。 而线程可以自动访问相同的内存地址空间和文件描述符
- 任务分解,交叉执行——有些问题可以被分解,从而提高整个程序的吞吐量(throughput)。一个单线程的进程在处理多任务时,会隐式的将这些任务串行化,因为只有一个控制线程。而在多线程情况下,进程中相互独立的任务就可以每个都分配一个线程,从而实现交叉执行。
- 缩短交互进程的响应时间——通过使用多线程,交互程序也可以缩短响应时间,多线程可以将程序中处理用户输入的部分和其他部分分开。
每个进程都含有表示执行环境所必须的信息,这些信息是
- 进程ID(用于标识该线程属于哪个进程)
- 一组寄存器值(register value)
- stack
- 调度优先级和策略(scheduling priority and policy)
- 信号屏蔽字(signal mask)
- error变量
- 线程特有数据(thread-specific data)
一个进程的所有信息对于该进程下的线程都是共享的,这些信息是:
- 执行程序的代码
- 全局和堆内存
- 栈
- 文件描述符
二、线程标识
与进程ID在整个系统中是唯一的不同,线程只有在它所属的上下文中才有意义。
线程的类型是pthread_t,实现时是用一个structure来代表pthread_t数据类型,所以呢?要比较两个线程的ID 就要采用函数。而且你是个结构体,很不方便打印线程值。
使用下面这个函数比较两个线程是否相同:
#include <pthread.h> int pthread_equal(pthread_t tid1, pthread_t tid2); Returns: nonzero if equal, 0 otherwise //相等返回非0值,否则返回0
线程本身使用下面这个函数返回线程值:
#include <pthread.h> pthread_t pthread_self(void); Returns: the thread ID of the calling thread
在上面这个图中,主线程将job放在一个work queue中,主线程会在每个待处理job结构中放置处理该作用的线程ID,然后每个线程通过比较线程ID值来移出标有自己线程ID的job.
三、线程创建
调用pthread_create函数创建线程:
#include <pthread.h> int pthread_create(pthread_t *restrict tidp,const pthread_attr_t *restrict attr,void *(*start_rtn)(void *), void *restrict arg); Returns: 0 if OK, error number on failure
- tidp指向的内存是新创建的线程ID值
- attr参数用于设置不同的线程参数,NULL代表线程具有默认属性
- 新创建的线程从start_rtn函数的地址开始运行。
线程创建时并不能保证是哪个线程先会运行: 是新创建的线程还是调用线程。新创建的线程可以访问进程的地址空间,并且继承调用线程的浮点环境和信号屏蔽字(signal mask),然而该线程的挂起信号集会被清除。