【Windows】线程同步的应用(第七篇)

目录

互斥锁

临界区

Windows平台下的CRITICAL_SECTION

示例代码

注意事项

C++11及以后的替代方案


互斥锁

在C++中,实现线程同步的一种常见方法是使用互斥锁(mutex)。互斥锁能够确保同一时刻只有一个线程可以访问某个共享资源。C++11及以后版本引入了<mutex>库,其中包含了std::mutex类以及与之相关的锁定机制(如std::lock_guardstd::unique_lock)。

以下是一个使用std::mutexstd::thread的简单线程同步示例:

#include <iostream>  
#include <thread>  
#include <mutex>  
  
// 全局互斥锁  
std::mutex mtx;  
  
// 共享资源  
int counter = 0;  
  
// 线程函数  
void increment(int n) {  
    for (int i = 0; i < n; ++i) {  
        // 锁定互斥锁  
        std::lock_guard<std::mutex> lck(mtx);  
        // 安全地访问共享资源  
        ++counter;  
        // 当std::lock_guard对象lck超出作用域时,自动释放互斥锁  
    }  
}  
  
int main() {  
    std::thread t1(increment, 1000);  
    std::thread t2(increment, 1000);  
  
    // 等待线程完成  
    t1.join();  
    t2.join();  
  
    std::cout << "Final counter: " << counter << std::endl;  
  
    return 0;  
}

在这个示例中,我们定义了一个全局的std::mutex对象mtx来保护共享资源counter。然后,我们定义了一个线程函数increment,它接受一个整数n作为参数,并将counter增加n次。在每次增加之前,我们使用std::lock_guard<std::mutex>来锁定互斥锁mtxstd::lock_guard是一个RAII(Resource Acquisition Is Initialization)风格的锁管理类,它在构造时自动锁定互斥锁,并在其析构时(即离开作用域时)自动释放互斥锁。这样,我们就无需手动调用lock()unlock(),从而减少了忘记释放锁的风险。

最后,我们在main函数中创建了两个线程t1t2,它们分别调用increment函数来增加counter的值。通过join()函数,我们等待这两个线程完成后再继续执行,最后打印出counter的最终值。由于我们使用了互斥锁来保护counter,因此最终打印的值应该是2000,而不是由于线程竞争而导致的不确定值。

临界区

在C++中,critical_section通常指的是一个用于多线程同步的机制,用于保护共享资源或代码段,以防止多个线程同时访问导致的竞态条件或数据不一致问题。然而,需要注意的是,critical_section这个术语并不是C++标准库(STL)中的直接组成部分,但在Windows编程中,它通常与CRITICAL_SECTION结构体相关联,该结构体用于管理临界区。

Windows平台下的CRITICAL_SECTION

在Windows平台上,CRITICAL_SECTION是一个用于线程同步的轻量级对象,它只适用于同一进程内的线程同步。使用CRITICAL_SECTION需要包含<windows.h>头文件,并按照以下步骤操作:

  1. 定义CRITICAL_SECTION对象:在代码中定义一个CRITICAL_SECTION类型的变量。

  2. 初始化CRITICAL_SECTION:使用InitializeCriticalSection函数初始化CRITICAL_SECTION对象。

  3. 进入临界区:在需要保护的代码段之前,使用EnterCriticalSection函数进入临界区。

  4. 离开临界区:在需要保护的代码段之后,使用LeaveCriticalSection函数离开临界区。

  5. 删除CRITICAL_SECTION:当不再需要CRITICAL_SECTION对象时,使用DeleteCriticalSection函数删除它。

示例代码

以下是一个Windows平台下使用CRITICAL_SECTION的示例代码:

#include <windows.h>  
#include <iostream>  
  
CRITICAL_SECTION cs;  
  
void CriticalSectionFunction() {  
    EnterCriticalSection(&cs);  
    // 在这里执行需要保护的代码  
    std::cout << "Thread " << GetCurrentThreadId() << " is in the critical section." << std::endl;  
    LeaveCriticalSection(&cs);  
}  
  
int main() {  
    InitializeCriticalSection(&cs);  
  
    // 创建并启动线程(示例中省略了线程创建和启动的代码)  
  
    // ...  
  
    // 等待所有线程完成(示例中省略了等待线程完成的代码)  
  
    // ...  
  
    DeleteCriticalSection(&cs);  
    return 0;  
}

注意事项

  • CRITICAL_SECTION是Windows特有的,不适用于跨平台的C++代码。
  • 在Linux等Unix-like系统中,通常使用互斥锁(如pthread_mutex_t)来实现类似的功能。
  • 使用CRITICAL_SECTION时,要确保每个EnterCriticalSection调用都有对应的LeaveCriticalSection调用,以避免死锁。
  • 在C++11及以后的版本中,推荐使用标准库中的std::mutexstd::lock_guard等同步原语,因为它们更加灵活且跨平台。

C++11及以后的替代方案

在C++11及以后的版本中,可以使用<mutex>头文件中的std::mutexstd::lock_guard等同步原语来替代CRITICAL_SECTION。这些同步原语是跨平台的,并且提供了更加灵活和强大的同步功能。

例如,使用std::mutexstd::lock_guard的示例代码如下:

#include <iostream>  
#include <thread>  
#include <mutex>  
  
std::mutex mtx;  
  
void protectedFunction() {  
    std::lock_guard<std::mutex> lock(mtx);  
    // 在这里执行需要保护的代码  
    std::cout << "Thread " << std::this_thread::get_id() << " is executing protected code." << std::endl;  
}  
  
int main() {  
    // 创建并启动线程(示例中省略了线程创建和启动的代码)  
  
    // ...  
  
    // 等待所有线程完成(示例中省略了等待线程完成的代码)  
  
    // ...  
  
    return 0;  
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱编程的小猴

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值