windows多线程同步--互斥量

简介:

关于互斥量的基本概念:百度百科互斥量

推荐参考博客:秒杀多线程第七篇 经典线程同步 互斥量Mutex

注意:互斥量也是一个内核对象,它用来确保一个线程独占一个资源的访问。互斥量与关键段的行为非常相似,并且互斥量可以用于不同进程中的线程互斥访问资源                                                                                                          本文地址

主要用到2个函数:CreateMutex,ReleaseMutex:

 

CreateMutex

函数功能:创建互斥量(注意与事件Event的创建函数对比)

函数原型:

HANDLE CreateMutex(

LPSECURITY_ATTRIBUTESlpMutexAttributes,

BOOLbInitialOwner,    

LPCTSTRlpName

);

第一个参数:表示安全控制,一般直接传入NULL。

第二个参数:用来确定互斥量的初始拥有者。如果传入TRUE表示互斥量对象内部会记录创建它的线程的线程ID号并将递归计数设置为1,由于该线程ID非零,所以互斥量处于未触发状态。如果传入FALSE,那么互斥量对象内部的线程ID号将设置为NULL,递归计数设置为0,这意味互斥量不为任何线程占用,处于触发状态。

第三个参数:用来设置互斥量的名称,在多个进程中的线程就是通过名称来确保它们访问的是同一个互斥量。

返回值:成功则返回一个表示互斥量的句柄,失败返回NULL。

 

ReleaseMutex

功能:释放互斥量

函数原型:

BOOL ReleaseMutex (HANDLEhMutex)

函数说明:

访问互斥资源前应该要调用等待函数,结束访问时就要调用ReleaseMutex()来表示自己已经结束访问,其它线程可以开始访问了。

 

另外还有个函数OpenMutex 可以打开其它进程中创建的互斥量

 

注意:主线程不要忘了删除互斥量

 

下面从一个例子说明:假设有三个线程都需要使用打印机,我们可以使用互斥量来控制,这样就可以保证每次只有一个线程在使用打印机

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include<string>
  #include<iostream>
  #include<process.h>
  #include<windows.h>
  using  namespace  std;
 
  //声明互斥量句柄
  HANDLE  hmu;
 
//线程绑定的函数返回值和参数是确定的,而且一定要__stdcall
unsigned __stdcall threadFun( void  *param)
{
     WaitForSingleObject(hmu, INFINITE); //等待互斥量
     cout<<*(string *)(param)<<endl;
     ReleaseMutex(hmu); //释放互斥量
     return  1;
}
 
 
int  main()
{
     //创建互斥量
     hmu = CreateMutex(NULL, FALSE, NULL);
 
     HANDLE  hth1, hth2, hth3;
     string s1 = "first" , s2 = "second" , s3 = "third" ;
 
     //创建线程
     hth1 = ( HANDLE )_beginthreadex(NULL, 0, threadFun, &s1, 0, NULL);
     hth2 = ( HANDLE )_beginthreadex(NULL, 0, threadFun, &s2, 0, NULL);
     hth3 = ( HANDLE )_beginthreadex(NULL, 0, threadFun, &s3, 0, NULL);
 
     //等待子线程结束
     WaitForSingleObject(hth1, INFINITE);
     WaitForSingleObject(hth2, INFINITE);
     WaitForSingleObject(hth3, INFINITE);
 
     //一定要记得关闭线程句柄
     CloseHandle(hth1);
     CloseHandle(hth2);
     CloseHandle(hth3);
 
     //千万别忘了删除互斥量
     CloseHandle(hmu);
}

 

互斥量有没有和临界区一样具有所有权属性呢,我们也从相同的例子来看:编写一个程序,开启3个线程,这3个线程的ID分别为A、B、C,每个线程将自己的ID在屏幕上打印10遍,要求输出结果必须按ABC的顺序显示;如:ABCABC….依次递推。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include<string>
  #include<iostream>
  #include<process.h>
  #include<windows.h>
  using  namespace  std;
  //声明3个互斥量句柄
HANDLE   hmu1, hmu2, hmu3;
 
//线程绑定的函数返回值和参数是确定的,而且一定要__stdcall
unsigned __stdcall threadFunA( void  *)
{
     for ( int  i = 0; i < 10; i++){
         WaitForSingleObject(hmu1, INFINITE); //等待互斥量
         cout<< "A" ;
         ReleaseMutex(hmu2); //释放互斥量
     }
     return  1;
}
unsigned __stdcall threadFunB( void  *)
{
     for ( int  i = 0; i < 10; i++){
         WaitForSingleObject(hmu2, INFINITE); //等待互斥量
         cout<< "B" ;
         ReleaseMutex(hmu3); //释放互斥量
     }
     return  2;
}
unsigned __stdcall threadFunC( void  *)
{
     for ( int  i = 0; i < 10; i++){
         WaitForSingleObject(hmu3, INFINITE); //等待互斥量
         cout<< "C" ;
         ReleaseMutex(hmu1); //释放互斥量
     }
     return  3;
}
 
int  main()
{
     hmu1 = CreateMutex(NULL, FALSE, NULL);
     hmu2 = CreateMutex(NULL, FALSE, NULL);
     hmu3 = CreateMutex(NULL, FALSE, NULL);
 
     HANDLE  hth1, hth2, hth3;
     //创建线程
     hth1 = ( HANDLE )_beginthreadex(NULL, 0, threadFunA, NULL, 0, NULL);
     hth2 = ( HANDLE )_beginthreadex(NULL, 0, threadFunB, NULL, 0, NULL);
     hth3 = ( HANDLE )_beginthreadex(NULL, 0, threadFunC, NULL, 0, NULL);
 
     //等待子线程结束
     WaitForSingleObject(hth1, INFINITE);
     WaitForSingleObject(hth2, INFINITE);
     WaitForSingleObject(hth3, INFINITE);
 
     //一定要记得关闭线程句柄
     CloseHandle(hth1);
     CloseHandle(hth2);
     CloseHandle(hth3);
 
     //删除互斥量
     CloseHandle(hmu1);
     CloseHandle(hmu2);
     CloseHandle(hmu3);
}

 

image

从结果看互斥量也具有所有权属性,即拥有互斥量的线程可以重复进入互斥量保护的区域






本文转自tenos博客园博客,原文链接:http://www.cnblogs.com/TenosDoIt/p/3601387.html,如需转载请自行联系原作者

目录
相关文章
|
2月前
|
Java 开发者 C++
Java多线程同步大揭秘:synchronized与Lock的终极对决!
Java多线程同步大揭秘:synchronized与Lock的终极对决!
62 5
|
2月前
|
安全 Java 开发者
Java多线程同步:synchronized与Lock的“爱恨情仇”!
Java多线程同步:synchronized与Lock的“爱恨情仇”!
82 5
|
2月前
|
Java 程序员
从0到1,手把手教你玩转Java多线程同步!
从0到1,手把手教你玩转Java多线程同步!
24 3
|
2月前
|
Java 测试技术
Java多线程同步实战:从synchronized到Lock的进化之路!
Java多线程同步实战:从synchronized到Lock的进化之路!
89 1
|
2月前
|
Java Windows
【Azure Developer】Windows中通过pslist命令查看到Java进程和线程信息,但为什么和代码中打印出来的进程号不一致呢?
【Azure Developer】Windows中通过pslist命令查看到Java进程和线程信息,但为什么和代码中打印出来的进程号不一致呢?
|
2月前
|
存储 Java 开发者
HashMap线程安全问题大揭秘:ConcurrentHashMap、自定义同步,一文让你彻底解锁!
【8月更文挑战第24天】HashMap是Java集合框架中不可或缺的一部分,以其高效的键值对存储和快速访问能力广受开发者欢迎。本文深入探讨了HashMap在JDK 1.8后的底层结构——数组+链表+红黑树混合模式,这种设计既利用了数组的快速定位优势,又通过链表和红黑树有效解决了哈希冲突问题。数组作为基石,每个元素包含一个Node节点,通过next指针形成链表;当链表长度过长时,采用红黑树进行优化,显著提升性能。此外,还介绍了HashMap的扩容机制,确保即使在数据量增大时也能保持高效运作。通过示例代码展示如何使用HashMap进行基本操作,帮助理解其实现原理及应用场景。
42 1
|
2月前
|
Java 调度 开发者
Java并发编程:解锁多线程同步的奥秘
在Java的世界里,并发编程是提升应用性能的关键所在。本文将深入浅出地探讨Java中的并发工具和同步机制,带领读者从基础到进阶,逐步掌握多线程编程的核心技巧。通过实例演示,我们将一起探索如何在多线程环境下保持数据的一致性,以及如何有效利用线程池来管理资源。无论你是初学者还是有一定经验的开发者,这篇文章都将为你打开新的视野,让你对Java并发编程有更深入的理解和应用。
|
3月前
|
安全 Java 程序员
Java 并发编程:解锁多线程同步的奥秘
【7月更文挑战第30天】在Java的世界里,并发编程是一块充满挑战的领域。它如同一位严苛的导师,要求我们深入理解其运作机制,才能驾驭多线程的力量。本文将带你探索Java并发编程的核心概念,包括线程同步与通信、锁机制、以及并发集合的使用。我们将通过实例代码,揭示如何在多线程环境中保持数据的一致性和完整性,确保你的应用程序既高效又稳定。准备好了吗?让我们一同踏上这段解锁Java并发之谜的旅程。
37 5
|
2月前
|
Java 开发者
解锁Java并发编程的秘密武器!揭秘AQS,让你的代码从此告别‘锁’事烦恼,多线程同步不再是梦!
【8月更文挑战第25天】AbstractQueuedSynchronizer(AQS)是Java并发包中的核心组件,作为多种同步工具类(如ReentrantLock和CountDownLatch等)的基础。AQS通过维护一个表示同步状态的`state`变量和一个FIFO线程等待队列,提供了一种高效灵活的同步机制。它支持独占式和共享式两种资源访问模式。内部使用CLH锁队列管理等待线程,当线程尝试获取已持有的锁时,会被放入队列并阻塞,直至锁被释放。AQS的巧妙设计极大地丰富了Java并发编程的能力。
35 0
|
2月前
|
Java UED
基于SpringBoot自定义线程池实现多线程执行方法,以及多线程之间的协调和同步
这篇文章介绍了在SpringBoot项目中如何自定义线程池来实现多线程执行方法,并探讨了多线程之间的协调和同步问题,提供了相关的示例代码。
330 0