互斥量的使用<转>

1、预备知识
   临界区非常适合同一进程中对数据的串行访问,它的速度很快。然而,也许你想要使某些应用程序与机器中的其它事件或者其它进程取得同步,这时你就要使用一些核心对象来同步线程。核心对象包括:
.进程
.线程
.文件
.文件变化通知(File Change notification)
.控制台输入(Console input)
.互斥量(Mutex)
.信号量(Semaphore)
.事件(Event)
   每个对象在任何时候都可以处于两种状态之一:有信号(Signaled)和无信号(not signaled)。线程能被置于睡眠状态直到一个对象变成有信号的。
  线程主要使用下面两个函数来使自己睡眠,以便等待核心对象变成有信号的:
DWORD WaitForSingleObject(
    HANDLE hHandle, // 等待的核心变量的句柄
    DWORD dwMilliseconds // 等候的时间,如果是0,只测试下状态,如果是INFINITE,则一直等待直到有信号
   );

DWORD WaitForMultipleObjects(
    DWORD nCount, //检查核心对象的数目,最大值为64
    CONST HANDLE *lpHandles, // 核心对象句柄数组的指针
    BOOL bWaitAll, // 等待的标志
    DWORD dwMilliseconds // 同WaitForSingleObject
   );
WaitForSingleObject的返回值为:
返回值: 定义: 含义:
WAIT_OBJECT_0 0x00000000 对象到达信号状态
WAIT_TIMEOUT 0x00000102 对象没有在dwMilliseconds内达到有信号状态
WAIT_ABANDONED 0x00000080 对象是一个互斥量,由于它被放弃了而达到了有信号状态
WAIT_FAILED 0xFFFFFFFF 发生了错误,可以调用GetLastError得到扩展错误信息
    WaitForMultipleObjects和WaitForSingleObject类似,不过它等待若干个对象变成有信号的或等一个列表对象的对象中的某一个变成有信号的。bWaitAll指定是等待列表中的一个达到状态还是等待所有的,若为True则等待所有的,为FALSE等待直到对象中至少一个变成有信号的。
WaitForMultipleObjects的返回值为:
返回值: 定义: 含义:
WAIT_OBJECT_0(WAIT_OBJECT_0+cObjects-1) 0x00000000 当是等待所有对象变成有状态时,这一值表明等待成功完成。当是等待任一对象时,返回值是变得有信号对象的在lpHandles所指句柄数组的下标
WAIT_TIMEOUT 0x00000102 对象或对象们没有在dwMilliseconds内达到有信号状态
WAIT_ABANDONED_0(WAIT_ABANDONED_0+cObjects-1) 0x00000080 对象是一个互斥量,由于它被放弃了而达到了有信号状态。返回值情况似类上面的WAIT_OBJECT_0,分两种情况。
WAIT_FAILED 0xFFFFFFFF 发生了错误,可以调用GetLastError得到扩展错误信息

2、互斥量
   互斥量和临界区很相似,只不过它们可以被用来同步多个进程间的数据访问。为此,两个进程间的某个线程必须拥有同一互斥量对象的进程相关句柄。

3、使用互斥量
  要使用互斥量,必须先调用CreateMutex 创建此互斥量:
HANDLE CreateMutex(
    LPSECURITY_ATTRIBUTES lpMutexAttributes,
    BOOL bInitialOwner,
    LPCTSTR lpName
   );
其中:
    lpMutexAttributes参数指向一个SECURITY_ATTRIBUTES结构,这个结构在98中将被忽略,在NT/2K中它指定一个安全描述,如果忽略这个,Mutex将得到一个缺省的安全描述。bInitialOwner参数如果为True表示此线程将拥有此互斥量,因此互斥量将处于无信号状态。任何在此互斥量上等待的线程都将被挂起,直到创建此互斥量的线程释放它。如果此参数为FALSE,就表示此互斥量不被任何线程拥有,因而创建后处于有信号状态。第一个等待此互斥量的线程将立刻获得此互斥量的所有权并继续运行。lpName参数要么是NULL,要么是一个标志互斥量的以0为结束符的字符串做为名字。
   在调用CreateMutex后要立即调用GetLasrError,如果返回值为ERROR_ALREADY_EXISTS,就表明没有创建新的互斥量对象。
    当要释放一个互斥量的所有权时调用BOOL ReleaseMutex(HANDLE hMutex)。和临界区一样,互斥量有着与之相联系的所有权计数,如果某线程拥有了互斥量再次调用WaitForSingleObject时,该互斥量的引用计数将增加,所以必须调用相同次数的ReleaseMutex来释放此互斥量。当互斥量使用完后调用CloseHandle关闭互斥量。

4、互斥量同步进程
   要使用互斥量来同步进程,两个进程中的某个进程必须拥有同一互斥量对象的进程相关句柄。可以通过两种方法获得此句柄。一是在第二个线程创建互斥量时使用与第一个互斥量一样的lpName,此时就不再创建新的互斥量而是返回标识已有互斥量的进程相关句柄。另一种获得的方法是使用
HANDLE OpenMutex(
    DWORD dwDesiredAccess, // MUTEX_ALL_ACCESS或SYNCHRONIZE(NT Only)
    BOOL bInheritHandle, // 指明此进程创建的任一子进程是否应该继承此互斥量。
    LPCTSTR lpName // 互斥量的名字
   );
   调用OpenMutex时,系统将扫描所有现存的互斥量,如果找到lpName指定的互斥量。就返回给调用线程,如果找不到就返回NULL。

<think>嗯,用户之前问过关于C++中多线操作bool变的问题,现在他们想知道Windows是否有类似std::atomic<bool>的操作。我需要先回顾之前的对话,确保回答一致。 用户可能是在开发跨平台应用,或者对Windows特有的线安全机制感兴趣。他们可能已经知道C++中的原子操作,现在想了解在Windows原生API中是否有对应的实现。 首先,我要确认Windows确实有原子操作的支持。比如Interlocked系列函数,比如InterlockedExchange和InterlockedCompareExchange。这些函数提供原子性的读写和交换操作,类似于std::atomic的功能。 接下来需要解释这些函数如何工作,以及它们如何保证操作的原子性。例如,InterlockedExchange可以原子地设置一个变的值,并返回原来的值,这在多线环境中非常有用。 还要比较Windows API和C++标准库的差异。比如,std::atomic<bool>是跨平台的,而Interlocked函数是Windows特有的。用户可能需要考虑移植性的问题,或者他们可能正在维护现有的Windows代码库,需要了解原生API。 此外,需要提到内存屏障的问题。Interlocked函数通常带有内存屏障,确保操作的顺序性和可见性,类似于std::atomic的内存顺序参数,比如memory_order_seq_cst。需要解释不同的内存顺序对性能的影响,以及在Windows中如何处理这些情况。 可能还需要给出代码示例,展示如何使用Interlocked函数来实现类似std::atomic<bool>的功能。例如,使用InterlockedCompareExchange来实现原子比较和交换操作,确保线安全。 用户可能想知道这些函数的具体使用场景和限制。例如,Interlocked函数只能用于特定类型,如32位或64位的变,而bool在C++中通常是1字节,可能需要换为LONG(32位)来使用这些函数。这可能导致一些注意事项,比如类型换和对齐问题。 还需要提醒用户,虽然Interlocked函数提供了原子操作,但在复杂场景下,可能需要结合其他同步机制,如临界区(CRITICAL_SECTION)或互斥(Mutex),来确保更复杂的线安全。 最后,总结一下,Windows提供了Interlocked系列函数作为原子操作的支持,类似于std::atomic,但需要根据具体需求选择合适的函数,并注意平台差异和类型换的问题。</think>在 Windows 系统中,虽然没有直接等同于 `std::atomic<bool>` 的类型,但可以通过 **原子操作 API(Interlocked Family Functions)** 实现类似功能。这些 API 提供了硬件级别的原子操作支持,确保对变的读写、修改在多线环境下是线安全的。 --- ### 一、Windows 原子操作 API #### 1. **核心函数** Windows 提供了一系列 `InterlockedXxx` 函数,专门用于对 **32 位或 64 位整数** 进行原子操作。对于 `bool` 类型(通常为 1 字节),需将其适配为 `LONG`(32 位)或 `BOOL`(4 字节)类型操作。 常用函数示例: | 函数 | 作用 | 对应 `std::atomic` 操作 | |-------------------------------|------------------------------|--------------------------------| | `InterlockedExchange` | 原子地设置值并返回旧值 | `store` + 返回旧值 | | `InterlockedCompareExchange` | 原子比较并交换(CAS操作) | `compare_exchange_strong` | | `InterlockedAnd` / `InterlockedOr` | 原子按位与/或操作 | `fetch_and` / `fetch_or` | --- #### 2. **原子操作示例** 假设需要实现一个原子 `bool` 标志位: ```cpp #include <Windows.h> // 使用 LONG 类型模拟原子 bool(0 表示 false,非 0 表示 true) volatile LONG g_flag = 0; // 原子设置为 true,并返回旧值 LONG old_value = InterlockedExchange(&g_flag, 1); // 原子比较并交换(若当前值为 0,则设置为 1) LONG expected = 0; LONG desired = 1; LONG result = InterlockedCompareExchange(&g_flag, desired, expected); ``` --- ### 二、与 `std::atomic<bool>` 的对比 | 特性 | Windows Interlocked API | `std::atomic<bool>` | |---------------------|------------------------------|-------------------------------| | **跨平台性** | 仅限 Windows | 跨平台(C++11 标准) | | **内存顺序控制** | 隐式包含全内存屏障(`MFENCE`)| 可通过参数指定(如 `memory_order_relaxed`) | | **数据类型限制** | 仅支持整数类型(LONG/LONG64)| 支持任意类型(包括 `bool`) | | **易用性** | 需手动管理类型换 | 类型安全,直接操作变 | --- ### 三、关键注意事项 1. **类型适配问题** - Windows 原子操作函数要求操作对象为 **对齐的 32/64 位整数**。若需操作 `bool`,需将其封装为 `LONG` 类型(例如 `0` 表示 `false`,`1` 表示 `true`)。 2. **内存屏障** - `InterlockedXxx` 函数默认包含 **全内存屏障**(类似 `std::memory_order_seq_cst`),确保操作前后的指令不会被重排序,且修改对所有线立即可见。 3. **性能优化** - 若仅需简单标志位操作,优先使用 `InterlockedExchange` 或 `InterlockedCompareExchange`;复杂逻辑仍需依赖锁(如 `CRITICAL_SECTION` 或 `SRWLOCK`)。 --- ### 四、完整示例(原子标志位) ```cpp #include <Windows.h> #include <iostream> volatile LONG g_flag = 0; DWORD WINAPI ThreadProc(LPVOID lpParam) { // 尝试原子设置标志位为 1 LONG old_val = InterlockedCompareExchange(&g_flag, 1, 0); if (old_val == 0) { std::cout << "线成功获取标志位!" << std::endl; } else { std::cout << "标志位已被其他线修改!" << std::endl; } return 0; } int main() { HANDLE hThread1 = CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL); HANDLE hThread2 = CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL); WaitForSingleObject(hThread1, INFINITE); WaitForSingleObject(hThread2, INFINITE); CloseHandle(hThread1); CloseHandle(hThread2); return 0; } ``` --- ### 五、总结 - **Windows 原生方案**:通过 `InterlockedXxx` 函数实现原子操作,需适配 `bool` 为整数类型。 - **推荐场景**: - 需要兼容旧版 Windows 代码或未使用 C++11 标准时。 - 对性能敏感且需直接调用底层 API 时。 - **通用建议**:优先使用 `std::atomic<bool>`(跨平台且类型安全),仅在必要时依赖 Windows 原生 API。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值