临界区的互斥控制

本文配套源码

一、前言

我正在研究线程的通讯,无奈有关这方面的资料实在太少,没办法我只好去啃MSDN,但是MSDN好像说得也不太清楚。所以那我就写了这么一个例子,以望对学习多线程编程起到引玉抛砖的作用。有个易懂的例子学起来总是容易很多。近来我正在复习那几个排序算法,于是就把这些算法写到了这里来作为线程的例子。同时也对几个通用的排序算法思想作了一些说明。

这个例子利用多线程使用不同的排序算法对数据进行排序,每一个线程使用不同的算法。主线程里使用快速排序QuickSort,其他四个算法分别建立四个子线程,在子线程中进行排序。因为每一个线程都要调用函数PrintResult把结果输出到显示器上,所以不同的线程就会争夺着向显示器输出,这样,不同线程的输出就会混合在一起,所以呢必须让线程一个接着一个输出。也就是必须对PrintResult进行互斥控

制。要进行互斥控制,则必须用到Event、Mutex、CrititicalSection、Semaphore等互斥控制量。这个例子可以使用Event、Mutex、CrititicalSection,你可以根据提示修改代码使用其中的一种互斥量进行测试。 我所写的例子没有使用MFC,用的都是SDK的WINAPI,如果使用MFC时有些许差别,但原理是一样的。而且MFC还把线程分成用户界面线程和工作者线程,实质上用户界面线程跟工作者线程的差别是,用户界面线程要继承的基类已经实现了消息循环,MFC帮你做了很多的消息处理和界面控制的工作。

一、WINAPI线程控制函数简介:有关详细说明请查看MSDN

1.1 线程建立函数 HANDLE CreateThread(
  LPSECURITY_ATTRIBUTES lpThreadAttributes,
  // 安全属性结构指针,可为NULL
  DWORD dwStackSize,
  // 线程栈大小,若为0表示使用默认值
  LPTHREAD_START_ROUTINE lpStartAddress,
  // 指向线程函数的指针
  LPVOID lpParameter,
  // 传递给线程函数的参数,可以保存一个指针值
  //所以,线程函数的参数只能是一个32位值
  //而且线程函数返回值也有规定,必须是unsigned long
  DWORD dwCreationFlags,
  // 线程建立是的初始标记,运行或挂起
  LPDWORD lpThreadId
  // 指向接收线程号的DWORD变量
);

1.2 临界资源控制函数:

1)事件对象的创建

事件对象的作用是为线程传送一个公共的事件信号,使用CreateEvent函数创建:

HANDLE CreateEvent(
  LPSECURITY_ATTRIBUTES lpEventAttributes,
  // 安全属性结构指针,可为NULL
  BOOL bManualReset,
  // 手动清除信号标记,TRUE在WaitForSingleObject后必须手动调
  //用RetEvent清除信号。
  //若为FALSE则在WaitForSingleObject后,系统自动清除事件信号
  BOOL bInitialState, // 初始状态,TRUE有信号,FALSE无信号
  LPCTSTR lpName // 信号量的名称,字符数不可多于MAX_PATH
  //如果遇到同名的其他信号量函数就会失败,如果遇到同类信号同名
  //也要注意变化
);
2)互斥量的创建

互斥量的作用是保证每次只能有一个线程获得互斥量而得以继续执行,使用CreateMutex函数创建: HANDLE CreateMutex(
  LPSECURITY_ATTRIBUTES lpMutexAttributes,
  // 安全属性结构指针,可为NULL
  BOOL bInitialOwner, // 当前建立互斥量是否占有该互斥量
  //TRUE表示占有,这样其他线程就不能获得此互斥量也就无法进入由
  //该互斥量控制的临界区。FALSE表示不占有该互斥量
  LPCTSTR lpName // 信号量的名称,字符数不可多于MAX_PATH
  //如果遇到同名的其他信号量函数就会失败,如果遇到同类信号同名
  //也要注意变化
);
3)临界区信号的初始化

使用前必须先初始化

VOID InitializeCriticalSection(
  LPCRITICAL_SECTION lpCriticalSection // 临界区变量指针
);
4)阻塞函数

如果等待的信号量不可用,那么线程就会挂起,直到信号可用线程才会被唤醒,该函数会自动修改信号,如Event,线程被唤醒之后

Event信号会变得无信号,Mutex、Semaphore等也会变。我们使用WaitForSingleObject函数等待信号,如果要等待多个信号可以使用WaitForMutipleObject函数。

DWORD WaitForSingleObject(
  HANDLE hHandle, // 等待对象的句柄
  DWORD dwMilliseconds // 等待毫秒数,INFINITE表示无限等待
);
二、实例讲解

时间: 2024-08-30 19:36:00

临界区的互斥控制的相关文章

临界区、互斥量、信号量

1.临界区:通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问. 2.互斥量:为协调共同对一个共享资源的单独访问而设计的. 3.信号量:为控制一个具有有限数量用户资源而设计. 临界区(Critical Section) 保证在某一时刻只有一个线程能访问数据的简便办法.在任意时刻只允许一个线程对共享资源进行访问.如果有多个线程试图同时访问临界区,那么在有一个线程进入后其他所有试图访问此临界区的线程将被挂起,并一直持续到进入临界区的线程离开.临界区在被释放后,其他线程可以继续抢占

进程、线程知识点总结和同步(消费者生产者,读者写者三类问题)、互斥、异步、并发、并行、死锁、活锁的总结

进程和程序: 进程:是个动态的概念,指的是一个静态的程序对某个数据集的一次运行活动,而程序是静态的概念,是由代码和数据组成的程序块而已. 进程5大特点:动态性,并发性,独立运行性,异步性,和结构化的特性. 在多道程序环境下,程序不能独立运行,操作系统所有的特征都是基于进程而体现的,只有进程可以在系统中运行,程序运行必须有进程才行.进程是操作系统里资源分配的基本单位,也是独立运行的基本单位,具有动态的特点,暂时出现的特点,而且一个进程产生之后,可以再次生成多个进程出来.也可以多个进程并发执行,也可

信号量、互斥体和自旋锁小结

概述 linuxn内核同步机制几种常用的方式,面试经常会被问道,这里做一个小结 [1]信号量 [2]互斥体 [3]自旋锁 [4]区别 1.信号量(semaphore) 又称为信号灯,本质上,信号量是一个计数器,用来记录对某个共享资源的存取情况,一般共享资源通过以下步骤          (1) 测试控制该资源的信号量(n). (2) 若此信号量的值为正,则允许进行使用该资源.进程将信号量减1. (3) 若此信号量为0,则该资源目前不可用,进程进入睡眠状态,直至信号量值大于0,进程被唤醒,转入步骤

操作系统:进程管理和IO控制

一.进程管理 进程管理包括进程控制,进程调度,进程同步与通信,死锁控制四个内容. (一)进程控制 进程是操作系统中运行的基本单位,包括程序段,数据段和进程控制段.操作系统通过进程控制块(PCB)管理进程.每一个PCB唯一标示一个进程.它存储进程的PID,UID,当前状态等信息,以及进程执行某一时刻的寄存器值,并且指向进程的数据段和程序段.OS把所有PCB链接为一个链表. 进程在刚刚被创建时出于new状态.OS负责申请一块存储空间作为该进程的PCB,在其中填上进程的信息,标示为ready,链接到P

基于AQS实现互斥信号(BooleanMutex)

背景   最近一个月都在做项目,我主要负责分布式任务的调度的功能,需要实现一个分布式的授权控制.   具体的需求:   1.  首先管理员启动整个任务,并设置执行权限   2.  工作节点收到消息后就会创建对应的线程,并开始执行任务(任务都是由一个管理员进行分配)   3.  运行过程中管理员需要临时中断某个任务,需要设置一个互斥信号,此时对应的工作节点都需要被阻塞,注意不是完全销毁 分析  先抛开分布式通讯这一块,首先从单个jvm如何实现进行分析, 简单点来说:  在单jvm中就是两种线程,一

互斥锁和条件变量

为了允许在线程或进程之间共享数据,同步时必须的,互斥锁和条件变量是同步的基本组成部分. 1.互斥锁 互斥锁是用来保护临界区资源,实际上保护的是临界区中被操纵的数据,互斥锁通常用于保护由多个线程或多进程分享的共享数据.一般是一些可供线程间使用的全局变量,来达到线程同步的目的,即保证任何时刻只有一个线程或进程在执行其中的代码.一般加锁的轮廓如下: pthread_mutex_lock() 临界区 pthread_mutex_unlock() 互斥锁API pthread_mutex_lock(pth

嵌入式 自旋锁、互斥锁、读写锁、递归锁

互斥锁(mutexlock): 最常使用于线程同步的锁:标记用来保证在任一时刻,只能有一个线程访问该对象,同一线程多次加锁操作会造成死锁:临界区和互斥量都可用来实现此锁,通常情况下锁操作失败会将该线程睡眠等待锁释放时被唤醒 自旋锁(spinlock): 同样用来标记只能有一个线程访问该对象,在同一线程多次加锁操作会造成死锁:使用硬件提供的swap指令或test_and_set指令实现:同互斥锁不同的是在锁操作需要等待的时候并不是睡眠等待唤醒,而是循环检测保持者已经释放了锁,这样做的好处是节省了线

操作系统进程互斥的模拟实现

问题描述 求教:Java怎么实现临界区进程互斥的模拟,,大概的编写代码思路,, 解决方案 解决方案二:这个进程间的互斥的话,感觉挺麻烦的,因为java并不能像c/c++那样直接操作内存你这样非得用java写的话,就需要用进程间通信机制了,java的有rmi,jms,异或自己写个socket等等模拟多个进程而sever模拟操作系统,在server中用个synchronized或者lock就可以说明是临界区了解决方案三:需要进程间互斥还是建议用c++做吧,java做比较复杂,性能也很差.

ASP.NET性能优化小结(ASP.NET&C#)

ASP.NET: 一.返回多个数据集 检查你的访问数据库的代码,看是否存在着要返回多次的请求.每次往返降低了你的应用程序的每秒能够响应请求的次数.通过在单个数据库请求中返回多个结果集,可以减少与数据库通信的时间,使你的系统具有扩展性,也可以减少数据库服务器响应请求的工作量. 如果用动态的SQL语句来返回多个数据集,那用存储过程来替代动态的SQL语句会更好些.是否把业务逻辑写到存储过程中,这个有点争议.但是我认为,把业务逻辑写到存储过程里面可以限制返回结果集的大小,减小网络数据的流量,在逻辑层也不