线程
上篇文章中讲了进程,各进程相互独立,有自己独立的虚拟地址空间,利用多进程编程和进程间通信等手段可以完成一些特定的工作。但多进程也有一些缺点,如下:
- 操作系统允许创建的最大进程数量是有限定的,不能无限制地创建进程。
- 在对进程进行调度时,进程的切换可能带来较严重的性能损耗。因为在进程切换时,操作系统需要为每个进程做保存现场和恢复现场的工作。保存现场包括:保存进程的各寄存器的值(包括通用寄存器、指令寄存器、堆栈指针、标志寄存器、段寄存器等),更新该进程的 PCB 并将其放入相应的队列中等。因此我们说进程切换时很「重」的!
因此,为了解决进程的这些问题,就出现了线程。线程被称为轻量级进程,因此可以看出线程的切换没有进程那么大的开销。其主要原因就是线程没有独立的虚拟地址空间,它依附于进程而存在。同一个进程中的所有线程共享代码区、数据区和堆,还有打开的文件描述符、信号处理函数、环境变量、用户 ID 等,每个线程私有的属性有栈、各种寄存器的值(硬件上下文)、errno 变量、信号屏蔽字和调度优先级等。
Linux 下线程相关的函数有:
- 线程创建:
int pthread_create(pthread_t _thread,const pthread_attr_t _attr,void _(_start_routine)(void_),void_ arg); - 线程终止:
void pthread_exit(void* retval);int pthread_cancel(pthread_t thread); - 线程等待:
int pthread_join(pthread_t thread,void** retval); - 线程分离:
int pthread_detach(pthread_t thread); - 获取线程id:
pthread_t pthread_self();
因为同一进程中所有线程共享全局变量和堆等数据,所有需要对各个线程进行同步操作。线程同步手段有:互斥量、信号量和条件变量。
-
互斥量相关函数:
- 初始化:
int pthread_mutex_init(pthread_mutex_t* restrict mutex,const pthread_mutexattr_t *restrice attr); - 销毁锁:
int pthread_mutex_destroy(pthread_mutex_t* mutex); - 加锁:
int pthread_mutex_lock(pthread_mutex_t* mutex);int pthread_mutex_trylock(pthread_mutex_t* mutex); - 解锁:
int pthread_mutex_unlock(pthread_mutex_t* mutex);
- 初始化:
-
条件变量相关函数:
- 初始化条件变量量:
int pthread_cond_init(pthread_cond_t _restrict cond,const pthread_condattr_t _restrict attr); - 销毁条件变量:
int pthread_cond_destroy(pthread_cond_t *cond); - 等待操作:
int pthread_cond_wait(pthread_cond_t _restrice cond,pthread_mutex_t _restrict mutex);int pthread_cond_timewait(pthread_cond_t _restrice cond,pthread_mutex_t _restrict mutex); - 唤醒操作:
int pthread_cond_signal(pthread_cond_t* cond);int pthread_cond_broadcase(pthread_cond_t* cond);
- 初始化条件变量量:
-
信号量相关函数:
- 初始化信号量:
int sem_init(sem_t* sem,int pshaeed,unsigned int value); - 销毁信号量:
int sem_destroy(sem_t* sem); - P操作:
int sem_wait(sem_t* sem);;int sem_trywait(sem_t* sem); - V操作:
int sem_post(sem_t* sem);
- 初始化信号量:
【完】