多线程目的是在单进程环境下执行多个任务。一个进程中的所有线程都可以访问该进程的组成部件,如文件描述符和内存。
单个资源在多个用户间共享,就必须处理一致性问题。
同一进程中的多条线程将共享该进程中的全部系统资源,如虚拟地址空间,文件描述符和信号处理等等。
但同一进程中的多个线程有各自的调用栈(call stack),自己的寄存器环境(register context),自己的线程本地存储(thread-local storage)。
通过__thread
关键字是GCC内置的线程局部存储设施,存储效率堪比全局变量,它保证该变量在每个线程中都有独立的实体,互不干扰
1.线程标识
每个线程有一个线程ID,并且这个ID只有在它所属的进程上下文中才有意义。
#include <pthread.h>
pthread_t pthread_self(void);//获取当前线程的线程ID
#include <pthread.h>
int pthread_equal(pthread_t tid1,pthread_t tid2);
//相等返回非0
//否则返回0
pid_t
用来标志进程,是一个非负整数,而pthread_t
则有可能是一个结构体(取决于实现)。
因此,在调用pthread_equal
的时候,参数必须严格是pthread_t
类型的变量,否则将会出现未定义的行为:
The pthread_equal() function shall return a non-zero value if t1 and t2 are equal; otherwise, zero shall be returned.
If either t1 or t2 are not valid thread IDs, the behavior is undefined.
2.创建线程
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);
线程的创建较为容易。
pthread_t * thread
指向线程创建成功时线程id所在的内存单元pthread_attr_t * attr
创建时属性start_routine
即run in thread回调,这是一个函数指针,指向函数返回void*
参数是void*
void *arg
即run in thread回调中的参数
3.线程终止
如果进程中的任意线程调用了exit
、_Exit
、_exit
函数,那么整个进程就会终止。
如果终止进程,则发送到线程的信号就会终止整个进程。
通过在线程中调用exit
系列函数发现,确实主进程也随着退出,那么如何优雅地退出?
1.直接返回 return
2.被其他线程取消
3.线程自己调用pthread_exit
而通过pthread_join
则可以知道return
或者pthread_exit
的状态码
#include <pthread.h>
void pthread_exit(void *retval);
#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);
另外,在APUE中提到一个很重要的点,使用pthread_exit
返回的变量不能是栈上变量,
我们知道每个线程有自己的栈,当某一个线程pthread_exit
返回后,栈空间可能被另外的线程所覆盖
为了解决这个问题,我们可以使用全局变量和malloc函数分配的堆变量。