互斥锁mutex:保证共享数据操作的完整性,保证在任一时刻只能有一个线程访问对象。锁有两个操作。一个P操作(上锁),一个V操作(解锁)。P和V都是原子操作,就是在执行P和V操作时,不会被插队。锁一般
使用信号量来实现的,mutex其实就是信号量=1。互斥量就是同一时间能够分给一个人,即S=1。S=10表示可以将信号量分给10个人来用。如果一共有20个人那么只能有10个人用,剩下10个人需要等待。
-- 在本项目中有两个操作添加用户和删除用户,信息都是存在消息队列当中,如果不上锁,这两个操作同时执行可能导致在消息队列当中信息错乱。在本项目头文件中加入#include <mutex>引入互斥锁。
unique_lock<mutex> lck(message_queue.m); // 访问共享资源-消息队列,上锁 (函数结束会自动解锁,所以版本5.0,add_user()和remove_user()都没用到解锁)
lck.unlock(); // 访问消息队列结束,解锁(版本5.0中在consume_task死循环中用到,因为这个函数是死循环,不解锁可能一直循环出不了函数,导致无法正常自动解锁)
条件变量condition_variable:条件变量一般和互斥锁搭配使用,条件变量用于在多线程环境中等待特定事件发生。
-- 在本项目中如果消息队列为空则等待,如果有添加用户和删除用户的操作则将消息队列唤醒。
message_queue.cv.wait(lck) // 队列为空,等待(版本2.0用到)
message_queue.cv.notify_all(); // 出现有添加或删除用户的操作Task操作进队列,唤醒
提高程序的并发性:多线程、多进程
多线程消耗少一点,效率差不多
cpu把时间平均分成若干份,系统进行调度,每个线程都要抢时间片,抢到就运行态,否则处于就绪态,线程实际走走停停,看不出
linux下线程本质上是轻量级的进程
内存四区图:
栈区,堆区,数据区,代码区
细分:
进程有自己独立的地址空间
如果是进程,就是多个线程共用一个地址空间
在一个地址空间中多个线程共享:代码区,堆区,全局数据区,打开的文件(文件描述符表)都是线程共享的
在一个地址空间中多个线程独享:每个线程都有属于自己的栈区,寄存器(内存中管理的)
线程是程序的最小执行单位,进程是操作系统中最小的资源分配单位
(1)每个进程应一个虚拟地址空间,一个进程只能抢一个CPU时间片
(2)一个地址空间中可以划分出多个线程,在有效的资源基础上,能够抢更多的CPU时间片(一个进程里的10个线程都能去抢cpu时间片)
CPU的调度和切换:线程的上下文切换比进程快的多
上下文切换:进程/线程分时复用CPU时间片,在切换之前会将上一个任务的状态进行保存,下次切换回这个任务的时候,加载这个状态继续运行
*** 任务从保存到再次加载这个过程就是一次上下文切换
标签:10,队列,线程,进程,操作,多线程 From: https://www.cnblogs.com/tkw123/p/17764299.html