第一点
线程的引入
接上节我们处理同时监测鼠标和键盘的例程,我们再提出二种解决方案-多进程处理、多线程处理
使用多进程处理时的优势
多进程可以实现并发操作,比如父进程创建子进程,两个进程可以分别读鼠标和键盘
CPU时分复用,单核心CPU可以实现宏观上的并行,微观上其实是串行!
实现多任务的系统需求
进程的劣势
进程间切换开销大
进程间通信麻烦而且效率低!
线程相对于进程的优势
线程技术保留了进程技术实现多任务的特性
线程的改进就是在线程间切换和线程间通信上提升了效率。
多线程在多核心CPU上面更有优势
第二点
创建一个线程程序(访问鼠标和键盘)
他的第一个参数为ptnread_t类型的指针,第二个参数为线程属性,一般般用不到。第三个参数为线程函数,下面代码就是,第四个是给线程函数的传参!
返回值正确就返回0
上面这个程序时用一个子线程的方式去读取键盘的内容,然后主线程的任务是读取鼠标内容!
由此,也引出来了线程的基本知识点:
线程是一种轻量级的进程,他是依附于进程而存在的。线程是参与内核调度的最小单元。一个进程中可以有多个线程。
除此之外,线程其实就像一个程序中多个函数间一样,所以他们之间很容易去高效率的通信,在多核心CPU架构下效率最大化!
第三点
线程相关函数与线程同步
线程相关函数
同步和互斥
同步是一种更为复杂的互斥,而互斥是一种特殊的同步。
也就是说,互斥是两个任务之间不可能同时运行,他们会相互排斥,必须等待一个线程运行完毕,另一个才能运行。而同步也是不能同步运行,但他必须是按照某种次序来运行相应的线程(也是一种互斥)!因此互斥均有唯一性和排他性,但互斥并不限制任务的运行顺序,及任务是无序的,而同步的任务之间则有顺序关系!
任务:用户从终端输入任意字符然后统计个数并显示,输入end则结束
普通做法
主线程获取用户输入并判断是否退出,子线程计数!
多线程处理(无同步)
这种情况下,当主函数一旦执行到子线程位置就会卡死,细细分析代码就可以理解!这就引入了一个问题,线程同步,也就是我们的子线程与主线程之间应该同步进行!
改进的方法应该是:主线程在接收到用户输入的字符串之后,并且确认不是end后,就去发信号激活子线程来计数,然后子线程本身应该是阻塞在他的函数里,等待被主线程激活后,去执行打印长度,等到打印完又回到阻塞命令,这样就实现了同步,下面来实现!
信号量
同步的方法有很多,下面我们用信号量的方法来实现!
初始化、激活、等待、销毁、
互斥锁
互斥锁又叫互斥量!
互斥锁和信号量的关系:可以认为互斥锁是一种特殊的信号量!
互斥锁主要用来实现关键段的保护!
在多任务操作系统中,同时运行的多个任务可能都需要使用同一种资源。这个过程有点类似于,公司部门的打印机被多人同时使用,如果不规定先后顺序的话,最终打印出来的资料肯定会混在一起。此时就需要这把锁,当我打印资料的时候,别人不能打印。
互斥锁就是用来干这个的,互斥锁就是一种简单的加锁的方法来控制对共享资源的访问,和互斥锁只有两种状态,上锁和解锁!
互斥锁的特点:
1. 原子性:把一个互斥量锁定为一个原子操作,这意味着操作系统(或pthread函数库)保证了如果一个线程锁定了一个互斥量,没有其他线程在同一时间可以成功锁定这个互斥量;
2. 唯一性:如果一个线程锁定了一个互斥量,在它解除锁定之前,没有其他线程可以锁定这个互斥量;
3. 非繁忙等待:如果一个线程已经锁定了一个互斥量,第二个线程又试图去锁定这个互斥量,则第二个线程将被挂起(不占用任何cpu资源),直到第一个线程解除对这个互斥量的锁定为止,第二个线程则被唤醒并继续执行,同时锁定这个互斥量。
条件变量(线程特有)
原理:
条件的检测是在互斥锁的保护下进行的,线程在改变条件状态之前必须先锁住互斥量。如果一个条件为假,这个线程就自动阻塞,并释放等待状态改变的互斥锁。
如果另一个线程改变了条件,他发给关联的条件变量,唤醒一个或多个等待他的线程,重新获得互斥锁,重新评判条件!和互斥锁配合使用
相关函数:
主线程
子线程