线程是CPU的最小调度单元,每个核上都可以运行一个线程。
多进程
缺点:
进程是互相隔离的,多进程之间的通信和同步是效率低。
CPU进行进程切换效率低
创建一个进程比创建线程耗费的内存多
优点:
单核CPU可以完成多任务,在宏观上并行。
线程:
优点:
线程保留了多进程的多任务特性,但是线程之间的通信效率更高,切换线程的效率也更高。
多核的CPU可以保证多线程可以同时运行在多个核上(CPU不能保证多个进程可以同时运行在多核上)
使CPU利用率更高
线程就是在保留了进程的多任务特性的基础上,优化了进程的通信和进程切换的效率。
线程创建与回收
(1)pthread_create 用来创造子线程的 创建成功立刻调用一次
(2)pthread_join 用来等待(阻塞)回收子线程
(3)pthread_detach 用来分离子线程,分离后主线程不必再去回收子线程
(4)pthread_attr_init 属性初始化的函数
线程取消
(1)pthread_cancel 一般都是主线程调用该函数去取消(让它赶紧死)子线程
(2)pthread_setcancelstate 子线程设置自己是否允处理cancel信号
(3)pthread_setcanceltype 取消模式(异步取消<立刻死> or 同步取消<等待适当时机死>)
线程函数退出相关
(1)pthread_exit与return退出
(2)pthread_cleanup_push 注册一个清理函数 清理锁
(3)pthread_cleanup_pop 注销清理函数
线程私有数据
int pthread_key_creadte(pthread_key_t *key,void (*destr_fuction) (void *)); 创建键值
int pthread_setspecific(pthread_key_t key,const void * pointer)); 设置
void * pthread_getspecific(pthread_key_t key); 获取
int pthread_key_delete(ptherad_key_t key); 删除
主线程退出:
主线程中如果从main函数返回或是调用了exit函数退出主线程,则整个进程终止,此时所有的其他线程也将终
主线程调用pthread_exit函数,则仅仅是主线程消亡,进程不会结束
线程取消:
线程取消就是向目标线程发送Cancel信号,但对这个信号的处理方式由线程自身决定(取消)。
if 是否接受取消信号 then
if 异步取消 then
立刻结束
else
运行到下个取消点结束(多数阻塞函数的调用位置都是取消点 pthread_join()、pthread_testcancel()、pthread_cond_wait()、pthread_cond_timedwait()、sem_wait()、sigwait())
end
end
触发终止线程的两种方式:
正常终止 :return 和主动pthread_exit(),
非正常终止:外部干扰导致退出
无论是那种方式退出 线程的资源都会被释放
对于非正常终止 要保证退出前资源可以正确清理 使用 pthread_cleanup_push/pthread_cleanup_pop。在两个函数中间的终止操作会调用清理函数,清理资源(如释放锁)
终止后清理资源方式:
线程为分离状态:操作系统自动回收资源。
pthread_join() :其他进程阻塞等待线程结束 并释放资源
其他:当线程退出时,线程占用的资源并不会释放。
什么是线程同步???
线程同步就是控制线程的执行顺序,保证线程安全(多个线程访问同时访问同一个数据)
同步方式:
互斥锁:
pthread_mutex_init pthread_mutex_destroy
pthread_mutex_lock pthread_mutex_unlock
信号量:
int sem_init
int sem_wait(sem_t *sem); 给信号量减1;对一个值为0的信号量调用sem_wait,这个函数将会等待直到有其它线程使它不再是0为止。
int sem_post(sem_t *sem); 给信号量的值加1;
int sem_destroy
条件变量
pthread_cond_init pthread_cond_destroy
pthread_cond_wait pthread_cond_signal/pthread_cond_broadcast
互斥锁不同,条件变量是用来等待而不是用来上锁的。条件变量用来自动阻塞一个线程,直到某特殊情况发生为止。一个线程等待"条件变量的条件成立"而挂起;另一个线程使"条件成立"(给出条件成立信号)。
多线程为什么需要同步??
为了解决多线程间共享数据问题,如果数据只是读那么没有影响。
为什么共享数据会发生问题???
对共享数据的操作如果不是原子不可打断的(单个汇编指令完成的操作为原子 或 加锁),那么在执行过程中线程可能会被挂起,其他线程也可以运行操作这个数据,就会导致线程见数据不安全。
例子:
x++和++x。
其实类似x++, x+=2, ++x这样的操作在多线程环境下是需要同步的。因为X86会按三条指令的形式来处理这种语句:从内存中读x的值到寄存器中,对寄存器加1,再把新值写回x 所处的内存地址。
例如有两个线程,它们按照如下顺序执行(注意读x和写回x是原子操作,两个线程不能同时执行):
time Thread 1 Thread 2
0 load eax, x
1 load eax x
2 add eax, 1 add eax, 1
3 store x, eax
4 store x, eax
中断的位置对程序的输出结果是有影响的,这就是导致多线程问题的根本原因。所以引入线程同步解决,保证某部分数据或代码的操作是原子的。
同步、互斥区别??
互斥不要求线程按一定顺序执行,同步是为了让线程按一定顺序执行。
同步是指在互斥的基础上(大多数情况),通过其它机制实现访问者对资源的有序访问。可以说同步是特殊的互斥。
互斥锁与信号量:
互斥锁是一种特殊的信号量,值只能是0 1 ,信号量值 可以是任意非0整数。互斥锁的加锁和解锁操作必须在同一线程中,信号量可以一个线程释放,另一个线程得到。
条件变量:条件变量用于同步 阻塞的等待某一条件满足 互斥锁是争夺资源 用于互斥
为什么要和互斥锁一起使用???
https://www.jb51.net/article/102764.htm