如何做招生网站,推广图片素材,企业形象设计包括哪些,哪个网站有适合小学生做的题目一、进程线程间的互斥相关的背景概念
临界资源#xff1a;多线程执行流共享的资源就叫做临界资源临界区#xff1a;每一个线程内部#xff0c;访问临界资源的代码#xff0c;就叫做临界区互斥#xff1a;任何时刻#xff0c;互斥保证有且只有一个执行流进入临界区#…一、进程线程间的互斥相关的背景概念
临界资源多线程执行流共享的资源就叫做临界资源临界区每一个线程内部访问临界资源的代码就叫做临界区互斥任何时刻互斥保证有且只有一个执行流进入临界区访问临界区资源通常对临界资源起保护作用原子性不会被任何调度机制打断的操作该操作只有两个状态要么完成要么未完成
二、互斥量 mutex
大部分情况下线程使用的数据都是局部变量变量的地址空间在线程栈空间中这种情况下变量归属于单个线程其他线程无法获得这种变量。但是有的时候很多变量都需要在线程间共享这样的变量称为共享变量可以通过数据的共享完成线程之间的交互。多个线程并发的操作共享变量会带来一些问题。
三、举例代码
3.1 先通过一个例子来看一看
#include iostream
#include unistd.h
#include pthread.h
#include vector
#include Thread.hppusing namespace Mypthread;int tickets 10000; // 票数void route(const std::string name)
{while (true){if (tickets 0){usleep(1000); // 微妙级用1毫秒表示抢票的时间printf(who: %s , get tickets: %d\n, name.c_str(), tickets);tickets--;}elsebreak;}
}// 抢票检验线程互斥
int main()
{mThread t1(thread-1, route);mThread t2(thread-2, route);mThread t3(thread-3, route);mThread t4(thread-4, route);t1.Start();t2.Start();t3.Start();t4.Start();t1.Join();t2.Join();t3.Join();t4.Join();return 0;
} 3.2 解释现象
3.2.1 判断的过程是不是一种计算 计算机常用的数据类型分为两种算术运算逻辑运算。CPU在计算过程中其操作过程不是原子的是需要分成好几个步骤的。
我们来拿逻辑判断来举例
第一步要先将数据移动到寄存器中第二步进行逻辑判断第三步将结果发出 在计算机中CPU有时只有一套但是寄存器中的数据是可以有多套的。多个线程根据时间片进行交替执行因为寄存器中的数据属于线程私有看起来是放在一套共有的寄存器中但是当线程要被切走的时候线程是需要带走自己的数据当线程回来的时候线程需要将数据进行恢复。 3.2.2 自减--的原理不是原子的
重读数据减减数据写回数据
3.2.3 在上面内容的基础上我们来解释一下这个现象 假设票数只剩下一张进程A看见还有一张进行买票但是在买票的过程中突然被切出进程B进入买票梅开二度在买票的过程中突然被切出...当进程A恢复线程进行减减操作票数为0退出进程B恢复线程记住现在tickets的票数为0减减重读数据将tickets为0读入将tickets减为负数之后的线程同理。
3.3 为什么可能无法获得争取结果 if 语句判断条件为真以后代码可以并发的切换到其他线程 usleep 这个模拟漫长业务的过程在这个漫长的业务过程中可能有很多个线程会进入该代码段 --ticket 操作本身就不是一个原子操作
3.4 我们来看一看汇编代码 通过汇编代码我们可以发现这种操作不是原子性操作而是分别对应于三条汇编指令
load将共享变量ticket从内存中加载到寄存器中update更新寄存器里面的值执行 -1 操作store更新值从寄存器写回共享内存ticket的内存地址
3.5 解决以上问题的措施
要解决以上问题需要做到三点
代码必须有互斥行为当代码进行临界区执行时不允许其他线程进入该临界区如果多个线程同时要求执行临界区的代码并且临界区没有线程执行那么只能允许一个线程进入给临界区如果线程不在临界区中执行那么线程不能组织其他线程进去临界区
四、互斥量 要做到上述三点本质上需要一把锁。Linux上提供的这把锁叫做互斥量。 4.1 互斥量的接口
4.1.1 互斥量的函数 函数的原型 #include pthread.hint pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrictattr);// 在全局开辟的或者在静态区中开辟的
pthread_mutex_t mutex PTHREAD_MUTEX_INITIALIZER 函数的功能 该函数用于C函数的多线程编程中互斥锁的初始化。在任何时候只允许一个线程进行访问。函数的参数 mutex指向要初始化的互斥锁的变量本身restrictattr指定了新建互斥锁的属性。如果参数restrictattr为空(NULL)则使用默认的互斥锁属性默认属性为快速互斥锁 。互斥锁的属性在创建锁的时候指定在LinuxThreads实现中仅有一个锁类型属性不同的锁类型在试图对一个已经被锁定的互斥锁加锁时表现不同。 下面是互斥锁的类型 PTHREAD_MUTEX_TIMED_NP这是缺省值也就是普通锁。当一个线程加锁以后其余请求锁的线程将形成一个等待队列并在解锁后按优先级获得锁。这种锁策略保证了资源分配的公平性。PTHREAD_MUTEX_RECURSIVE_NP嵌套锁允许同一个线程对同一个锁成功获得多次并通过多次unlock解锁。如果是不同线程请求则在加锁线程解锁时重新竞争。PTHREAD_MUTEX_ERRORCHECK_NP检错锁如果同一个线程请求同一个锁则返回EDEADLK否则与PTHREAD_MUTEX_TIMED_NP类型动作相同。这样就保证当不允许多次加锁时不会出现最简单情况下的死锁。PTHREAD_MUTEX_ADAPTIVE_NP适应锁动作最简单的锁类型仅等待解锁后重新竞争。 函数的返回值 函数成功完成之后会返回零其他任何返回值都表示出现了错误 4.1.2 互斥量的初始化
方法1静态分配
// 在全局开辟的或者在静态区中开辟的
pthread_mutex_t mutex PTHREAD_MUTEX_INITIALIZER
方法2动态分配
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrictattr);
4.1.3 互斥量的销毁
销毁互斥量需要注意使用 PTHREAD_ MUTEX_ INITIALIZER 初始化的互斥量不需要进行销毁 对于一个已经加锁的互斥量不要进行销毁对于已经销毁的互斥量要确保后面不会有线程在尝试加锁。 函数的原型 #include pthread.hint pthread_mutex_destroy(pthread_mutex_t* mutex);函数的功能 进行互斥量的销毁对于一个已经加锁的互斥量不要进行销毁对于已经销毁的互斥量要确保后面不会有线程在尝试加锁。 函数的参数 mutex指向要初始化的互斥锁的变量本身 函数的返回值 函数成功完成之后会返回零其他任何返回值都表示出现了错误 4.1.4 互斥量的加锁和解锁
4.1.4.1 互斥量的加锁阻塞调用 函数的原型 #include pthread.hint pthread_mutex_lock(pthread_mutex_t* mutex); 函数的功能 该函数用于对互斥锁进行加锁操作。它阻塞调用线程直到可以获得互斥锁为止。如果互斥锁已经被其他线程锁定则调用线程将被阻塞直到互斥锁被解锁。函数的参数 mutex指向要初始化的互斥锁的变量本身 函数的返回值 返回值为0表示成功加锁返回值为非零值表示失败 4.1.4.2 互斥量的加锁非阻塞调用 函数的原型 #include pthread.hint pthread_mutex_trylock(pthread_mutex_t* mutex); 函数的功能 该函数是pthread_mutex_lock函数的非阻塞版本。如果mutex参数所指定的互斥锁已经被锁定的话调用pthread_mutex_trylock函数不会阻塞当前线程而是立即返回一个值来描述互斥锁的状况。 函数的参数 mutex指向要初始化的互斥锁的变量本身 函数的返回值 函数成功完成之后会返回零其他任何返回值都表示出现了错误 4.1.4.3 互斥量的解锁 函数的原型 #include pthread.hint pthread_mutex_unlock(pthread_mutex_t* mutex); 函数的功能 该函数用于解锁互斥锁它接收一个指向互斥锁的指针作为参数并将该互斥锁解锁。 函数的参数 mutex指向要初始化的互斥锁的变量本身 函数的返回值 函数成功完成之后会返回零其他任何返回值都表示出现了错误 总结 所谓对临界资源进行保护本质上是对临界区代码进行保护我们对所有资源经访问本质都是通过代码进行访问。保护资源本质上就是想办法把访问资源的代码进行保护起来。
4.1.5 对抢票代码进行加锁操作
4.1.5.1 全局变量的锁
代码如下
int tickets 10000; // 票数// 建立一个全局范围的锁
pthread_mutex_t mutex;void route(const std::string name)
{while (true){// 加锁pthread_mutex_lock(mutex);if (tickets 0){usleep(1000); // 微妙级用1毫秒表示抢票的时间printf(who: %s , get tickets: %d\n, name.c_str(), tickets);tickets--;// 解锁pthread_mutex_unlock(mutex);}else{// 解锁pthread_mutex_unlock(mutex);break;}}
}
代码执行结果 4.1.5.2 局部变量的锁
// 在Thraed类中加入锁的变量class ThreadDate{public:ThreadDate(const std::string name, pthread_mutex_t* lock):_name(name),_lock(lock){}public:std::string _name;pthread_mutex_t* _lock;};
4.1.6 对锁进行封装 在想要保护的临界区前面进行定义一个锁即可因为随着函数范围的释放该锁也会跟着解锁。
class LockGuard
{
public:LockGuard(pthread_mutex_t* mutex):_mutex(mutex){pthread_mutex_lock(_mutex);}~LockGuard(){pthread_mutex_unlock(_mutex);}private:pthread_mutex_t* _mutex;
};
4.1.7 解决历史问题
加锁的范围的粒度一定要尽量小任何线程要进行抢票都要先申请锁原则上不应该有例外所有线程申请锁前提是所有线程都要看到这把锁锁本身也是共享资源加锁的过程必须是原子的原子性要么不做要么做就要做完没有中间状态就是原子性如果线程申请锁失败了我的线程要被阻塞如果线程申请锁成功了继续向后进行运行如果线程申请锁成功了执行临界区的代码在执行临界区的代码期间可以进行切换其他线程无法进入因为我虽然被切换但是我没有进行释放我可以放心的执行完毕没有人可以打扰我。 总结所以对于其他线程要么我没有申请锁要么我释放了所对其他线程才有意义。我访问临界区对于其他线程是原子的。
4.3 对互斥量的原理实现
我们对于锁来说重要的函数是
int pthread_mutex_lock(pthread_mutex_t* mutex);
如何理解申请锁成功允许进入临界区申请锁成功pthread_mutex_lock函数会返回。
如何理解申请锁失败不允许进行临界区 申请锁时报pthread_mutex_lock函数不会返回。
4.4 互斥量的实验原理探究 在经过上面的例子中我们已经可以意识到单纯的 i 操作或者 i 操作都不是原子的有可能会有数据一致性的问题所以为了实现互斥锁的操作大多数体系结构都提供了swap操作和exchange操作指令。 swap操作和exchange操作指令这种指令就是原子性的该指令的作用是把寄存器和内存单元的数据济宁相互交换由于只有一条指令保证了原子性即使是多处理平台进行访问访问内存的总线周期也有先后一个处理器上的交换指令执行时另一个交换指令只能等待总线周期。
现在我们来看一下lock和unlock的伪代码进行查看
先来看一看lock中的操作 lock在内存中开辟一段空间我们可以在这段空间中放入一些值来使线程具有互斥性。比如当lock中的数字为1说明我们可以进行该临界区同时将lock中的数字进行交换变为0当lock中的数字变为0说明我们不能进入该临界区需要进行挂起等待然后重新进行lock的判断。 举个例子首先这个锁处于无人状态。现在有一个线程A进行lock中将lock中的数字和al寄存器的数字进行交换然后现在al寄存器中的数字为1大于0说明我们可以进入临界区中。之后随着时间片的轮转线程A要被切走对于线程A在CPU寄存器中的所有数据也要跟着一起切走然后此时lock中的数字为依旧为0其他线程中的al寄存器中的数字也为0所以其他线程无法进行该临界区也就是将其他线程全部都锁在了外面只有当线程A完成打开锁之后其他线程才能进入该临界区中。 再来看一看umlock中的操作 我们在来看一看这个unlock操作等待线程A操作完之后我们需要直接将数字1赋值给mutex内存中之后唤醒其他等待Mutex的线程。 总结 CPU的寄存器只有一套被所有的线程共享但是寄存器里面的数据属于执行流的上下文属于执行零私有的数据CPU在执行代码的时候一定要有对应的执行载体线程或者进程数据在内存中被所有线程共享 把数据从内存中移动到CPU寄存器中本质上就是把数据从共享变为线程私有。 文章转载自: http://www.morning.djpps.cn.gov.cn.djpps.cn http://www.morning.xzsqb.cn.gov.cn.xzsqb.cn http://www.morning.jxjrm.cn.gov.cn.jxjrm.cn http://www.morning.dtmjn.cn.gov.cn.dtmjn.cn http://www.morning.iterlog.com.gov.cn.iterlog.com http://www.morning.yxdrf.cn.gov.cn.yxdrf.cn http://www.morning.xtlty.cn.gov.cn.xtlty.cn http://www.morning.zyrcf.cn.gov.cn.zyrcf.cn http://www.morning.zczkm.cn.gov.cn.zczkm.cn http://www.morning.wtcbl.cn.gov.cn.wtcbl.cn http://www.morning.rlxg.cn.gov.cn.rlxg.cn http://www.morning.wzwpz.cn.gov.cn.wzwpz.cn http://www.morning.rykx.cn.gov.cn.rykx.cn http://www.morning.nnwpz.cn.gov.cn.nnwpz.cn http://www.morning.qfplp.cn.gov.cn.qfplp.cn http://www.morning.yrblz.cn.gov.cn.yrblz.cn http://www.morning.mhbcy.cn.gov.cn.mhbcy.cn http://www.morning.pjrql.cn.gov.cn.pjrql.cn http://www.morning.syfty.cn.gov.cn.syfty.cn http://www.morning.srbsr.cn.gov.cn.srbsr.cn http://www.morning.bwttp.cn.gov.cn.bwttp.cn http://www.morning.yfmlj.cn.gov.cn.yfmlj.cn http://www.morning.zpkfb.cn.gov.cn.zpkfb.cn http://www.morning.xjmyq.com.gov.cn.xjmyq.com http://www.morning.xdxpq.cn.gov.cn.xdxpq.cn http://www.morning.rwqk.cn.gov.cn.rwqk.cn http://www.morning.qbrdg.cn.gov.cn.qbrdg.cn http://www.morning.drzkk.cn.gov.cn.drzkk.cn http://www.morning.alwpc.cn.gov.cn.alwpc.cn http://www.morning.qlrwf.cn.gov.cn.qlrwf.cn http://www.morning.lrjtx.cn.gov.cn.lrjtx.cn http://www.morning.rynq.cn.gov.cn.rynq.cn http://www.morning.rbgqn.cn.gov.cn.rbgqn.cn http://www.morning.mtrz.cn.gov.cn.mtrz.cn http://www.morning.krlsz.cn.gov.cn.krlsz.cn http://www.morning.whclz.cn.gov.cn.whclz.cn http://www.morning.rynqh.cn.gov.cn.rynqh.cn http://www.morning.rckdq.cn.gov.cn.rckdq.cn http://www.morning.dbfwq.cn.gov.cn.dbfwq.cn http://www.morning.tpnx.cn.gov.cn.tpnx.cn http://www.morning.cljpz.cn.gov.cn.cljpz.cn http://www.morning.gtcym.cn.gov.cn.gtcym.cn http://www.morning.xsetx.com.gov.cn.xsetx.com http://www.morning.fnssm.cn.gov.cn.fnssm.cn http://www.morning.wfspn.cn.gov.cn.wfspn.cn http://www.morning.ltspm.cn.gov.cn.ltspm.cn http://www.morning.vattx.cn.gov.cn.vattx.cn http://www.morning.hrpmt.cn.gov.cn.hrpmt.cn http://www.morning.hrzhg.cn.gov.cn.hrzhg.cn http://www.morning.qrzqd.cn.gov.cn.qrzqd.cn http://www.morning.nxhjg.cn.gov.cn.nxhjg.cn http://www.morning.lysrt.cn.gov.cn.lysrt.cn http://www.morning.xcyzy.cn.gov.cn.xcyzy.cn http://www.morning.blznh.cn.gov.cn.blznh.cn http://www.morning.rbsxf.cn.gov.cn.rbsxf.cn http://www.morning.pqnps.cn.gov.cn.pqnps.cn http://www.morning.pjfmq.cn.gov.cn.pjfmq.cn http://www.morning.bxhch.cn.gov.cn.bxhch.cn http://www.morning.xqcgb.cn.gov.cn.xqcgb.cn http://www.morning.hhrpy.cn.gov.cn.hhrpy.cn http://www.morning.kkdbz.cn.gov.cn.kkdbz.cn http://www.morning.dbbcq.cn.gov.cn.dbbcq.cn http://www.morning.xwrhk.cn.gov.cn.xwrhk.cn http://www.morning.gsyns.cn.gov.cn.gsyns.cn http://www.morning.rzmkl.cn.gov.cn.rzmkl.cn http://www.morning.kdtdh.cn.gov.cn.kdtdh.cn http://www.morning.mfmbn.cn.gov.cn.mfmbn.cn http://www.morning.knnhd.cn.gov.cn.knnhd.cn http://www.morning.tthmg.cn.gov.cn.tthmg.cn http://www.morning.qhczg.cn.gov.cn.qhczg.cn http://www.morning.zglrl.cn.gov.cn.zglrl.cn http://www.morning.cjqcx.cn.gov.cn.cjqcx.cn http://www.morning.lmfxq.cn.gov.cn.lmfxq.cn http://www.morning.zdbfl.cn.gov.cn.zdbfl.cn http://www.morning.ncqzb.cn.gov.cn.ncqzb.cn http://www.morning.nwgkk.cn.gov.cn.nwgkk.cn http://www.morning.lfdzr.cn.gov.cn.lfdzr.cn http://www.morning.cniedu.com.gov.cn.cniedu.com http://www.morning.qnbzs.cn.gov.cn.qnbzs.cn http://www.morning.kzhgy.cn.gov.cn.kzhgy.cn