线程

上篇文章中讲了进程,各进程相互独立,有自己独立的虚拟地址空间,利用多进程编程和进程间通信等手段可以完成一些特定的工作。但多进程也有一些缺点,如下:

  • 操作系统允许创建的最大进程数量是有限定的,不能无限制地创建进程。
  • 在对进程进行调度时,进程的切换可能带来较严重的性能损耗。因为在进程切换时,操作系统需要为每个进程做保护现场和恢复现场的工作。保护现场包括:保存进程的各寄存器的值(包括通用寄存器,指令寄存器,堆栈指针,标志寄存器,段寄存器等),更新该进程的PCB并将其放入相应的队列中等。因此我们说进程切换时很“重”的!

<!--more-->

因此,为了解决进程的这些问题,就出现了线程。线程被称为轻量级进程,因此可以看出线程的切换没有进程那么大的开销。其主要原因就是线程没有独立的虚拟地址空间,它依附于进程而存在。同一个进程中的所有线程共享代码区,数据区和堆,还有打开的文件描述符,信号处理函数,环境变量,用户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);