一、进程线程概念
程序
程序就是编译好的二进制文件。
什么是进程
在程序员眼中,进程就是程序的一次运行;而在操作系统眼中,进程是对运行时程序的封装,是系统进行资源调度和分配的的基本单位,实现了操作系统的并发。
什么是线程
线程是轻量级的进程,是线程是进程的子任务,系统资源调度和分派的基本单位,用于保证程序的实时性,实现进程内部的并发。
进程线程区别
1,一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。线程依赖于进程而存在。
2,进程号唯一,线程号可能重复。
3,进程拥有独立的内存空间,而同一进程的多个线程地址空间是共享的。
4,创建销毁切换进程的开销大于线程的开销。
5,进程调试起来较线程的调试简单得多。
6,进程间不会相互影响 ;线程一个线程挂掉将导致整个进程挂掉。
二、线程进程通信
进程通信
管道
1,普通管道 PIPE
1) 它是半双工的(即数据只能在一个方向上流动),具有固定的读端和写端
2) 它只能用于具有亲缘关系的进程之间的通信(也是父子进程或者兄弟进程之间)
2,命名管道 FIFO:
1)FIFO 可以在无关(没有血缘关系)的进程之间交换数据。
2)FIFO 有路径名与之相关联(有实体文件),它以一种特殊设备文件形式存在于文件系统中。
信号
信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。(可以用来回收子进程)
共享内存
它使得多个进程可以访问同一块内存空间,不同进程可以及时看到对方进程中对共享内存中数据得更新。
套接字(本地套接字)
socket 也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同主机之间的进程通信。
线程通信
互斥量
采用互斥对象机制,只有拥有互斥对象的线程才有访问公共资源的权限。因为互斥对象只有一个,所以可以保证公共资源不会被多个线程同时访问
条件变量
条件变量不是锁,配合互斥量等待某一条件的发生。
信号量
其实就是升级版的互斥量,它允许多个线程在同一时刻去访问同一个资源。
信号
通过通知操作的方式来保持多线程同步。(在多线程中慎用,调试容易出问题)
三、多线程通信的锁
互斥锁
互斥锁有两种初始化方式
pthread_mutex_t mutex;
pthread_mutex_init(&mutex,NULL);//方法一
mutex=PTHREAD_MUTEX_INITIALIZER;//方法二
加锁
pthread_mutex_lock(&mutex);
解锁
pthread_mutex_unlock(&mutex);
值得一提的是boost库中有mutex的封装,直接能加锁解锁。
mutex m1;//使用不需要初始化
m1.lock();//加锁
m1.unlock();//解锁
还有就是unique_lock<mutex>
mutex m1;
{
unique_lock<mutex> lk(m1);//变量定义就相当于给m1加锁,销毁就相当于解锁
//实现一个这样的类也不难,变量构造的时候初始化加锁,析构销毁了就给解锁
}
条件变量
初始化
pthread_cond_t cond;
cond=PTHREAD_COND_INITIALIZER;//方法一
pthread_cond_init(&cond,NULL);//方法二
阻塞等待一个条件变量
阻塞线程,将已经上锁的mutex解锁,解除阻塞后会对mutex加锁
pthread_cond_timedwait(&cond,&mutex);
唤醒至少一个阻塞在条件变量上的线程
pthread_cond_signal(&cond);
唤醒全部阻塞在条件变量上的线程
pthread_cond_broadcast(&cond);
值得一提的就是std库中的封装
condition_variable cv;
int flag=1;
cv.wait(lk,[]{return flag==0;});//阻塞等待,后面是一个lambda表达式(返回bool值)可以省略
cv.notify_one()//唤醒至少一个阻塞在条件变量上的线程
cv.notify_all();//唤醒全部阻塞在条件变量上的线程
提示
避免多进程和多线程同时使用,避免多线程的时候使用信号,这样调试起来比较困难。
多线程能避免用锁就避免用锁,用锁的话尽量减少临界区,这样能提高效率。