临界区

Visual C++ 11 中新的并发功能

岁酱吖の 提交于 2020-01-01 02:47:12
最新的 C++ 迭代(称为 C++11,在去年通过了国际标准化组织 (ISO) 的审批)形式化了一组新库和一些保留字以处理并发。 许多开发者以前都在 C++ 中使用过并发功能,但都是通过第三方的库,即,通常直接公开 OS API。 Herb Sutter 在 2004 年 12 月宣告“免费的性能午餐”结束,因为禁止 CPU 制造商通过物理能耗和增加碳排放量来生产更快的 CPU。 由此进入了当前主流的多核时代,一种新的实现,而 C++(标准组件)为适应此类变化取得了重要的飞跃。 本文下面的内容将分成两节,另外还有一些小节。 第一节,从并行执行开始,介绍允许应用程序并行运行独立或半独立活动的技术。 第二节,从同步并发执行开始,探讨同步机制,这些活动通过同步方式处理数据,以避免出现争用情况。 本文基于即将推出的 Visual C++ 版本(现在称为 Visual C++ 11)中包括的功能。 当前版本 (Visual C++ 2010) 中已提供其中部分功能。 尽管本文不提供关于为并行算法建模的指南,也不提供关于所有可用选项的详尽文档,但却全面介绍了新的 C++11 并发功能,内容丰富详实。 并行执行 当您对数据建模和设计算法时,很自然地就会按照具有一定顺序的步骤指定这些建模和设计过程。 只要性能位于可接受的范围内,这就是最值得推荐的方案,因为它通常更易于理解,而这符合维护代码的要求。

Visual C++ 11 中新的并发功能

£可爱£侵袭症+ 提交于 2020-01-01 02:44:36
最新的 C++ 迭代(称为 C++11,在去年通过了国际标准化组织 (ISO) 的审批)形式化了一组新库和一些保留字以处理并发。 许多开发者以前都在 C++ 中使用过并发功能,但都是通过第三方的库,即,通常直接公开 OS API。 Herb Sutter 在 2004 年 12 月宣告“免费的性能午餐”结束,因为禁止 CPU 制造商通过物理能耗和增加碳排放量来生产更快的 CPU。 由此进入了当前主流的多核时代,一种新的实现,而 C++(标准组件)为适应此类变化取得了重要的飞跃。 本文下面的内容将分成两节,另外还有一些小节。 第一节,从并行执行开始,介绍允许应用程序并行运行独立或半独立活动的技术。 第二节,从同步并发执行开始,探讨同步机制,这些活动通过同步方式处理数据,以避免出现争用情况。 本文基于即将推出的 Visual C++ 版本(现在称为 Visual C++ 11)中包括的功能。 当前版本 (Visual C++ 2010) 中已提供其中部分功能。 尽管本文不提供关于为并行算法建模的指南,也不提供关于所有可用选项的详尽文档,但却全面介绍了新的 C++11 并发功能,内容丰富详实。 并行执行 当您对数据建模和设计算法时,很自然地就会按照具有一定顺序的步骤指定这些建模和设计过程。 只要性能位于可接受的范围内,这就是最值得推荐的方案,因为它通常更易于理解,而这符合维护代码的要求。

并发编程之互斥锁

此生再无相见时 提交于 2019-12-27 00:39:54
原子性问题的源头是线程切换,如果能够禁用线程切换那不就能解决这个问题了吗?而操作系统做线程切换是依赖 CPU 中断的,所以禁止 CPU 发生中断就能够禁止线程切换。 在早期单核 CPU 时代,这个方案的确是可行的,而且也有很多应用案例,但是并不适合多核场景。这里我们以 32 位 CPU 上执行 long 型变量的写操作为例来说明这个问题,long 型变量是 64 位,在 32 位 CPU 上执行写操作会被拆分成两次写操作(写高 32 位和写低 32 位,如下图所示)。 在单核 CPU 场景下,同一时刻只有一个线程执行,禁止 CPU 中断,意味着操作系统不会重新调度线程,也就是禁止了线程切换,获得 CPU 使用权的线程就可以不间断地执行,所以两次写操作一定是:要么都被执行,要么都没有被执行,具有原子性。但是在多核场景下,同一时刻,有可能有两个线程同时在执行,一个线程执行在 CPU-1 上,一个线程执行在 CPU-2 上,此时禁止 CPU 中断,只能保证 CPU 上的线程连续执行,并不能保证同一时刻只有一个线程执行,如果这两个线程同时写 long 型变量高 32 位的话,那就有可能出现诡异 Bug 。 “同一时刻只有一个线程执行”这个条件非常重要,我们称之为互斥。如果我们能够保证对共享变量的修改是互斥的,那么,无论是单核 CPU 还是多核 CPU,就都能保证原子性了。 锁模型如下图:

CEvent,CSemaphore,CCriticalSection,CMutex

浪尽此生 提交于 2019-12-26 22:43:54
一、用CEvent实现线程同步 事件对象(Event)是最简单的同步对象,它包括有信号和无信号两种状态。在线程访问某一资源之前,也许需要等待某一事件的发生,这时用事件对象最合适。例如,只有在通信端口缓冲区收到数据后,监视线程才被激活。 MFC中,CEvent类提供了对事件的支持。CEvent对象有两种类型:人工事件和自动事件。对于自动事件,当其获得信号后,就会释放下一个可用的线程。一个自动CEvent对象在被至少一个线程释放后会自动返回到无信号状态;而人工事件对象获得信号后,释放所有可利用线程,直到调用成员函数ReSetEvent()将其设置为无信号状态时为止。 在创建CEvent对象时,默认创建的是自动事件 CEvent类的构造函数原型如下: CEvent(BOOL bInitia11y0wn=FALSE,//若bInitiallyOwn为TRUE,则使CMultilock类对象和CSingleLock类对象的线程可用;否则,要访问资源的线程必须等待。该参数的默认值为FALSEo BOOL bManualReset = FALSE,//指定要创建的CEvent对象是属于手工事件还是自动事件。为TRUE,则为手工事件;否则为自动事件。该参数默认值为FALSE o LPCTSTR lpszName=NULL,//指定要创建的事件对象的名,如果该事件对象将跨进程使用

Python 中的线程与进程(四)

爷,独闯天下 提交于 2019-12-23 03:16:15
由于大多数程序不需要有多线程的能力,所以在Python启动的时候并不支持多线程。也就是说,Python中支持多线程所需要的数据结构特别是GIL并没有创建。当Python虚拟机启动的时候,多线程处理并没有打开,而仅仅支持单线程。只有当程序中使用了如thread.start_new_thread等方法的时候,python才知道需要有多线程处理的支持,此时,python虚拟机才会自动创建多线程处理所需要的数据结构与GIL。 生成和终止线程(由于thread模块比较低级,不被推荐使用,所以就不说了) 1 使用threading.Thread类(构造函数:Thread(group = None, target = None, name = None, args = (), kwargs = {})   使用threading模块来创建线程是很简单的。简单地说,只要继承threading.Thread,然后在__init__方法中,调用threading.Thread类的__init__方法,重写类的run方法就可以了。 import threading class MyThread(threading.Thread): def __init__(self): threading.Thread.__init__(self) def run(self): pass thread =

嵌入式操作系统进入临界区是否影响中断的接受?

空扰寡人 提交于 2019-12-21 05:52:15
在ucos,Freertos中常常会有进入临界区,以保证当前的操作不可被打断,确保操作关键代码的安全。 进入临界区 关键代码操作 假设发生A类型中断 退出临界区 那么A中断还能够接受到吗? 进入临界区,关闭中断,中断发生,打开中断,这个过程中会发生什么呢? 显然,关闭中断期间,CPU不可能去响应中断,再次打开中断的时候,如果在关闭中断期间,发生了中断,发生的中断被记录下来,开启中断时候,中断控制器会再次响应这些被记录的中断。 STM32在使用时有时需要禁用全局中断,比如MCU在升级过程中需禁用外部中断,防止升级过程中外部中断触发导致升级失败。 ARM MDK中提供了如下两个接口来禁用和开启总中断: __disable_irq(); // 关闭总中断 __enable_irq(); // 开启总中断 但测试发现这样一个问题,在关闭总中断后,如果有中断触发,虽然此时不会引发中断,但在调用__enable_irq()开启总中断后,MCU会立即处理之前触发的中断。这说明__disable_irq()只是禁止CPU去响应中断,没有真正的去屏蔽中断的触发,中断发生后,相应的寄存器会将中断标志置位,在__enable_irq()开启中断后,由于相应的中断标志没有清空,因而还会触发中断。所以要想禁止所有中断,必须对逐个模块的中断进行Disable操作,由于每个模块中断源有很多

Linux内核设计与实现

▼魔方 西西 提交于 2019-12-16 09:14:49
第8章 内核同步方法 总述 1)应用程序和内核都应该防止共享资源被并发访问 2)保护共享资源的困难:单处理器时,只有在中断发生的时候,或在内核代码显式地请求重新调度,执行另一个任务时,数据才可能并发访问,比较简单。内核支持多处理器后,内核代码完全可以同时运行在两个或更多的处理器上,如果不加保护,运行在两个不同处理器上的内核代码完全可能在同一时刻里并发访问共享数据。Linux内核已经支持抢占式内核,即调度程序可以在任何时刻抢占正在运行的内核代码,重新调度其他的进程执行。 8.1 临界区和竞争条件 1)临界区:访问和操作共享数据的代码段。 2)避免在临界区中并发访问:必须保证这些代码原子地执行,即代码在执行结束前不可被打断。 3)竞争条件:两个执行线程处于同一个临界区 4)同步:避免并发和防止竞争条件 8.2 加锁 1)简单的竞争条件:原子操作 2)复杂的竞争条件:加锁 需求:处理一个队列上的所有服务请求, 实现:假设用一个链表表示,链表中的每一个节点代表一个请求。有两个函数来操作此队列,一个函数将请求添加到队列尾部,另一个函数从队列头删除情况,然后处理它。 问题:并发访问问题。内核各个部分都会调用到这两个函数,内核会频繁地将在队列中加入请求,从队列中删除和处理请求。对请求队列的操作要用到多条指令。如果一个线程试图读取队列,而正好另一个线程正在处理该队列

二元信号量、互斥量和临界区之间的区别

☆樱花仙子☆ 提交于 2019-12-10 04:05:52
二元信号量   是最简单的一种锁,适合只能被唯一一个线程独占访问的资源;对于允许多个线程并发访问的资源,多元信号量简称信号量; 互斥量   和二元信号量很类似,资源仅同时允许一个线程访问,但和信号量不同的是,信号量在整个系统可以被任意线程获取并释放;也就是说哪个线程锁的,要哪个线程解锁。 临界区    是比互斥量更加严格的同步手段。在术语中,把临界区的获取称为进入临界区,而把锁的释放称为离开临界区。与互斥量和信号量的区别:   (1)互斥量和信号量字系统的任何进程都是可见的。   (2)临界区的作用范围仅限于本进程,其他进程无法获取该锁。    来源: https://www.cnblogs.com/bugutian/p/5087538.html

进程间的mutex

耗尽温柔 提交于 2019-12-06 08:48:29
设两个进程共用一个临界资源的互斥信号量mutex=1,当mutex=-1时表示()。 一个进程进入了临界区,另一个进程等待 没有一个进程进入临界区 两个进程都进入临界区 两个进程都在等待 互斥信号量不采用自旋锁的方式实现,mutex初始值为1,当一个准备进入临界区时,mutex - 1 = 0,该进程进入临界区; 另一个进程准备进入临界区时,mutex - 1 = -1,mutex < 0时将该进程挂起到mutex的列表中,等待被唤醒。 因此一个进程已经进入临界区,另一个进程在等待。 对于两个并发进程,设互斥信号量为mutex,若mutex=0,则 表示没有进程进入临界区 表示有一个进程进入临界区 表示有一个进程进入临界区,另一个进程等待进入 表示有两个进程进入临界区 解析:本题考查互斥信号量的性质,mutex初值为1,表示允许一个进程进入临界资源,当由一个进程进入临界区且没有进程等待进入时,mutex减1,变为0,|mutex|为等待进入的进程数。就此题而言,当mutex=1时表示没有进程进入临界区;当mutex=-1时表示有一个进程进入临界区,另一个进程等待进入,答案选B。 来源: https://www.cnblogs.com/Stephen-Qin/p/11973819.html

STM32F104ZET6之ucosⅢ临界区保护

谁说胖子不能爱 提交于 2019-12-06 00:57:28
UCOSⅢ对临界区的处理方法 1.中断开关的方式 临界区一旦被访问,那么就关闭所有中断,防止执行过程被更高级中断打断 保证了数据的同步性,但可能会导致一些紧急事件未能及时处理 OS_ENTER_CRITICAL()简单地关中断,OS_EXIT_CRITICAL()简单地开中断。 这种方式虽然简单高效,但无法满足嵌套的情况。 如果有多层临界区保护,在退出内层临界区时就会开中断,使外层的临界区也失去保护。 不推荐使用。 2.压栈的方式 临界区在被访问过程中,被中断打断,就对该状态进行压栈处理,保证各个事件按等级正常运行, 但数据无法保证同步性,压栈的数据在出栈时,上次的中断可能已经修改了数据,将数据出栈没有什么意义, 不推荐使用。 3.保存在本地局部变量. 在关中断前,使用局部变量保存中断状态。 一般都用模式三,使用方法如下 //1.定义一个局部变量cpu_sr CPU_SR cpu_sr = (CPU_SR)0; //也可直接调用宏定义一个局部变量cpu_sr //关于这个宏,在cpu.h中303行左右,如下 //#if (CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL) //#define CPU_SR_ALLOC() CPU_SR cpu_sr = (CPU_SR)0 //#else //#define