Windwos下的线程互斥和同步

AI权益加码!Claude Code、Cursor等20+工具免费用! 购周边限时加赠Coding Plan Lite,畅享主流AI工具!学习进阶更高效! 阅读详情

关键字: Windows 、线程、互斥、同步

摘要 :分析了“互斥”与“同步”在概念上的差异,简单介绍了 Windows 平台下的互斥、同步机制,详细讨论了生产者-消费者模型及其变形,以及容易出错的方面。

 

概述

       网 络多媒体应用系统同时包括网络传输、媒体采集和显示、媒体数据编解码、人机接口等多个紧密联系而又相对独立的组成部分,各部分之间需要并行协作才能正常运 行,因此大量采用了多线程的运行模式。多线程模式对资源的访问提出了特殊要求。本文分析了线程“互斥”与“同步”在概念上的差异,简单介绍了 Windows 平台下的互斥、同步机制,详细讨论了生产者-消费者模型及其变形,以及容易出错的方面。

 

互斥与同步

       互斥和同步是两个紧密相关而又容易混淆的概念。

       互斥 :是指某一资源同时只允许一个访问者对其进行访问,具有唯一性和排它性。但互斥无法限制访问者对资源的访问顺序,即访问是无序的。

同步 :是指在互斥的基础上(大多数情况),通过其它机制实现访问者对资源的有序访问。在大多数情况下,同步已经实现了互斥,特别是所有写入资源的情况必定是互斥的。少数情况是指可以允许多个访问者同时访问资源,如“ 第一类读写者模型 ”。

 

Windows 下的互斥同步机制

       Windows 下提供了多种内核对象实现线程、进程间的同步和互斥,常用的有:

       关键节 Critical Section ):关键节不是内核对象,在用户态实现了同一进程中线程的互斥。由于使用时不需要从用户态切换到核心态,所以速度很快( X86 系统上约为 20 个指令周期),但其缺点是不能跨进程同步,同时不能指定阻塞时的等待时间,只能无限等待。

       互斥体 :( Mutex ):互斥体实现了和关键节类似的互斥功能,但区别在于:互斥体是内核对象,可以实现跨进程互斥,但需要在用户态和核心态之间切换,速度比关键节慢得多( X86 系统上约为 600 个指令周期),同时可以指定阻塞时的等待时间。

       事件 Event ):事件也是内核对象,具有“信号态”和“无信号态”两种状态。当某一线程等待一个事件时,如果事件为信号态,将继续执行,如果事件为无信号态,那么线程被阻塞。线程能够指定阻塞时的等待时间。

信号量 Semaphore ):信号量是一个资源计数器,当某线程获取某信号量时,信号量计数首先减 1 ,如果计数小于 0 ,那么该线程被阻塞;当某县城释放某信号量时,信号量计数首先加 1 ,如果计数小于或等与 0 ,那么唤醒某被阻塞的线程并执行之。对信号量的总结如下:

1.               如果计数器 m 大于 0 ,表示还有 m 个资源可以访问,此时信号量线程等待队列中没有线程被阻塞,新的线程访问资源也不会被阻塞;

2.               如果计数器 m 等与 0 ,表示没有资源可以访问,此时信号量线程等待队列中没有线程被阻塞,但新的线程访问资源会被阻塞;

3.               如果计数器 m 小于 0 ,表示没有资源可以访问,此时信号量线程等待队列中有 absm )个线程被阻塞,新的线程访问资源会被阻塞;

信号量常被用于保证对多个资源进行同步访问。

 

生产者-消费者模型

       生产者-消费者模型是指:

1.   生产者进行生产将物品放入仓库,同一时间只能有一个生产者将物品放入仓库,如果仓库满,生产者等待。

2.   消费者从仓库中取出物品,同一时间只能有一个消费者取出物品,如果仓库空,消费者等待;

3.   生产者将物品放入仓库时消费者不能同时取;

4.   消费者取物品时生产者不能放入物品;

总之,就是生产者群体或消费者群体内部是互斥的,两个群体之间是同步的。

 

当只有一个生产者、消费者时,由于同一群体内部不需要互斥,所以只需在群体之间实 现同步即可。例如可以使用两个 EventCriticalSectionMutexSemaphore 实现同步;

 

如果有多个生产者和消费者,那么情况会复杂些,需要一个 EventCriticalSectionMutex 实现线程之间的互斥,需要两个 Semaphore 实现两个线程群体间的同步。一个例子如下:

         HANDLE m_S_Producer ;  // Semaphore

         HANDLE m_S_Consumer ; // Semaphore

HANDLE m_E_Queue ;    // Event

 

// 假设仓库最多容纳 M 个物品,开始仓库为空

         m_S_Producer = CreateSemaphore ( NULL , M , M , NULL );  // 初始计数为 M

         m_S_Consumer = CreateSemaphore ( NULL , 0, M , NULL );  // 初始计数为 0

         m_E_Queue = CreateEvent ( NULL , FALSE , TRUE , NULL ); // 自动类型,初始状态为信号态

 

生产者

         if ( WaitForSingleObject ( m_S_Producer , WaitTime ) == WAIT_OBJECT_0 )

         {

                   if ( WaitForSingleObject ( m_E_Queue , WaitTime ) == WAIT_OBJECT_0 )

                   {

                            // OK now, put product

                 

                            // relase comsumer’s semaphore

                            ReleaseSemaphore ( m_S_Consumer , 1, NULL );

            // set event to signal

                            SetEvent ( m_E_Queue );

 

                            return TRUE ;

                   }

                   else // wait event time out

                   {

                            // not put product so release producer

                            ReleaseSemaphore ( m_S_Producer , 1, NULL );

                            SetEvent ( m_E_Queue );

 

                            return FALSE ;

                   }

         }

         else // wait semaphore time out

         {

                   return FALSE ;

}

 

消费者

         if ( WaitForSingleObject ( m_S_Consumer , WaitTime ) == WAIT_OBJECT_0 )

         {

                   if ( WaitForSingleObject ( m_E_Queue , WaitTime ) == WAIT_OBJECT_0 )

                   {

                            // OK now, Get product then

                           

             // releasee productor’s semaphore

                            ReleaseSemaphore ( m_S_Producer , 1, NULL );

             // set event to signal

                            SetEvent ( m_E_Queue );

 

                            return TRUE ;

                   }

                   else // wait event time out

                   {

                            // not get product   so release Consumer

                            ReleaseSemaphore ( m_S_Consumer , 1, NULL );

                            SetEvent ( m_E_Queue );

                            return FALSE ;

                   }

         }

         else // wait semaphore time out

         {

                   return FALSE ;

}

 

特别需要注意的是 ,在该模型中,对互斥量(本例为 m_E_Queue )的等待必须放在第二个等待位置,否则可能将造成线程死锁。考虑这样的情况:仓库已满,没有任何线程访问。某一时刻,生产者放入物品,首先等待 m_E_Queue 并通过,且将 m_E_Queue 置于无信号态,然后等待 m_S_Produce 时被阻塞。 这时某一消费者欲取物品,无论在什么情况下,都将在等待m_E_Queue时被阻塞,从而相互等待造成死锁。在释放同步对象时则位置不受限制。

 

多个生产者一个消费者

    这时一种常用的变形。如果仓库是一个 队列 (先进先出) 此时消费者内部将不需要互斥。

 

消费者

         if ( WaitForSingleObject ( m_S_Consumer , WaitTime ) == WAIT_OBJECT_0 )

         {

                            // OK now, Get product then

                           

             // releasee productor’s semaphore

                            ReleaseSemaphore ( m_S_Producer , 1, NULL );

                       return TRUE ;

         }

         else // wait semaphore time out

         {

                   return FALSE ;

}

此时可能出现消费者、生产者同时访问资源的情况,但生产者群体和消费者群体之间的同步机制,以及队列的先进先出机制将保证即使消费者、生产者同时访问资源,也不会发生冲突。

 

多个消费者一个生产者 的情况类似。

Windows线程互斥过程代码 环境vc6.0 该代码演示了线程互斥的框架代码,编译环境VC++6.0 立即下载

相关推荐

操作系统实验之进程同步互斥课件

该压缩包里含有详细的实验介绍,并附有课件完成以后的代码,帮助很大

进程的同步互斥习题(含部分题目的参考答案).doc

进程的同步互斥习题(含部分题目的参考答案).doc

编程实现进程(线程同步互斥

Windows等操作系统下,使用的VC、VB、java或C等编程语言,采用进程(线程同步互斥的技术编写程序实现生产者-消费者问题或哲学家进餐问题或读者-写者问题或自己设计一个简单进程(线程同步互斥的实际问题。

[转]Windwos下的线程互斥同步

 Windwos下的线程互斥同步 关键字: Windows线程互斥同步摘要:分析了“互斥”与“同步”在概念上的差异,简单介绍了Windows平台下的互斥同步机制,详细讨论了生产者-消费者模型及其变形,以及容易出错的方面。 概述       网络多媒体应用系统同时包括网络传输、媒体采集显示、媒体数据编解码、人机接口等多个紧密联系而又相对独立的组成部分,各部分之间需

宋雷的技术博客 1153

windows线程同步互斥

windows线程同步互斥。临界区对象,事件内核对象,互斥量,信号量

new9232的博客 1441

【生产者-消费者问题】Windows线程互斥同步

【生产者-消费者问题】Windows线程互斥同步(操作系统课设作业)

有为肥宅的博客 1879

操作系统——Windows 线程互斥同步

操作系统课设:实验四

CSH__的博客 1313

Windows多线程数据同步互斥的有关知识

 对于操作系统而言,在并行程序设计中难免会遇到数据同步共享的问题,本文针对这个问题,以windows系统为例回顾一下资源同步的相关问题。要点如下: 1.同步数据共享 数据征用 2.同步原语 1.互斥临界区 2.自旋锁 3.信号量 4.读写锁 5.屏障 6.原子操作与无锁代码 3.进...

weixin_34126557的博客 221

线程互斥同步

线程同步的方式机制 (1)临界区(Critical Section)、互斥对象(Mutex):主要用于互斥控制;都具有拥有权的控制方法,只有拥有该对象的线程才能执行任务,所以拥有,执行完任务后一定要释放该对象。 (2)信号量(Semaphore)、事件对象(Event):事件对象是以通知的方式进行控制,主要用于同步控制!   第一方法,实现互斥,主要控制共享资源,只能被一个线程访问;但无...

shaoshuai—AI-DATA 285

Windwos中的线程同步

Windwos中的线程同步 Windwos中的线程同步 2019年5月23日 9:57 Windows操作系统的运行方式(程序运行方式)为"双模式操作"(Dual-mode Operation)。 用户模式(User mode):运行应用程序的基本模式,禁止访问物理设备,而且会限制访问的内存区域 内核模式(Kern...

weixin_43464294的博客 115

Windows核心编程系列》谈谈用户模式下的线程同步

系统中的线程必须访问系统资源,如堆、串口、文件、窗口以及其他资源。如果一个线程独占了对某个资源的访问,其他线程无法完成工作。我们也必须限制线程在任何时刻都能访问任何资源。比如在一个线程读内存时要限制其他线程对此块内存进行写入。   线程之间的通信很重要,尤其是在以下两种情况下:   1:需要让多个线程同时访问一个共享资源,同时不能破坏资源的完整性。   2:一个线程需要通知其他线程某项任务已经完成。   线程同步包括许多方面,windows提供了许多基础设施使线程同步变得容易。   用户模式下的线程同步:方法一,原子访问   线程同步的一大部分与原子访问有关。所谓原子访

windwos线程同步的几种方式

大家都知道开多线程的的目的是为了提高程序的处理效率,但是多线程会存在访问同一个资源会出现数据混乱,当然多个线程只读这一个共享资源肯定是没有问题的,但是修改的话肯定会有问题,所以需要同步的概念windows提供了多个同步对象 同步模式有两种: 1三环(用户模式):原子操作, 关键段 2内核同步对象:事件, 信号, 互斥体 三环的同步手段,效率明显高于内核同步对象 ...

qq_35426012的博客 255

Windwos下的互斥锁,事件以及事件的手动重置自动重置的区别

事件的自动重置:两个线层同时访问一个函数,该函数会对全局变量进行操作,用事件进行互斥,假设这个事件初始化有信号 在经过WAITFORSIGALOBJECT()后事件就会变为没有信号,另外一个线程无法进去,第一个线程操作完需设置为有信号 setEvent(events);使事件变成有信号后,第二个线程才能进入。 事件的手动重置:相当于一个用户(线层)经过WaitForSingleObject...

huangtianyi1994的博客 757

Windows线程同步方法

 1. 互斥    利用互斥对象可以实现多个线程对某资源的互斥访问,互斥对象是内核对象,包含以下组成部分:一个线程ID(当前拥有该互斥对象的线程)、一个计数器(线程拥有互斥对象的次数)一个使用计数。    对于互斥对象的使用有一条原则:谁拥有谁释放。   1)创建互斥对象HANDLE CreateMutex{   LPSECURITY_ATTRIBUTES lpMutexAttributes,

非壹即零 1614

用C++Windows互斥对象(Mutex)来实现线程同步

用C++Windows互斥对象(Mutex)来实现线程同步锁 准备知识:1,内核对象互斥体(Mutex)的工作机理,WaitForSingleObject函数的用法,这些可以从MSDN获取详情;2,当两个或 更多线程需要同时访问一个共享资源时,系统需要使用同步机制来确保一次只有一个线程使用该资源。Mutex 是同步基元,它只向一个线程授予对共享资源的独占访问权。如果一个线程

junecauzhang的专栏 756
上一篇: 关于STL/ATL/WTL之间的区别
下一篇: 英文自我介绍模板推荐
Gary@Tokyo
博客等级 码龄20年 315粉丝 78原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值