互斥器mutex

    对于多线程,当一个线程1在访问一个资源A的时候,
    其他线程不能再对资源A进行访问!
    必须等到线程1不在访问资源A的时候,其他线程才能去访问资源A。
==>这就需要做:在多个线程之间做一个同步!

 

 1.创建一个互斥器对象

    hMutex=CreateMutex(NULL,TRUE,NULL);
    参数1(安全属性):
            NULL-使用默认的安全性;
    参数2(当前创建的这个互斥器的初始拥有者):
            TRUE-调用者创建这个互斥器,调用线程获得互斥器的所有权;
            FALSE-当前调用线程不获取互斥器的所有权;
    参数3(互斥器名称):给创建出来的互斥器/对象,起的一个名字;
            NULL-创建一个没有名字的互斥对象;
    返回值:这个互斥对象的句柄;

    2.重要内容声明
    2.1 互斥对象(mutex)属于内核对象,它能够确保线程
        拥有对单个资源的互斥访问权;
    2.2 互斥对象包含:1个使用数量、1个线程ID、1个计数器;
    2.3 ID:用于标识系统中的哪个线程拥有当前的互斥对象;
        计数器:用于指明该线程拥有互斥器对象的次数;

 

#include <windows.h>
//#include <iostream.h>
#include <iostream>

using namespace std;

DWORD WINAPI Fun1Proc(
  LPVOID lpParameter   // thread data
);DWORD WINAPI Fun2Proc(
  LPVOID lpParameter   // thread data
);
int index=0;
int tickets=100; //此时,2个线程会访问同一个变量,所以会出问题
HANDLE hMutex;
void main()
{
    HANDLE hThread1;
    HANDLE hThread2;
    hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
    hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);
    CloseHandle(hThread1);
    CloseHandle(hThread2);
    /*while(index++<1000)
        cout<<"main thread is running"<<endl;*/
   
    hMutex=CreateMutex(NULL,TRUE,NULL);
    /*hMutex=CreateMutex(NULL,TRUE,"tickets");
    if(hMutex)
    {
        if(ERROR_ALREADY_EXISTS==GetLastError())
        {
            cout<<"only instance can run!"<<endl;
            return;
        }
    }
    WaitForSingleObject(hMutex,INFINITE);
    ReleaseMutex(hMutex);
    ReleaseMutex(hMutex);*/
    //为了让线程1和2有时间卖票,这里将主线程睡眠4s钟(主线程会在4s以后,继续执行)
    Sleep(4000); //这时候,主线程是不占用CPU时间的
    //Sleep(10);
}

DWORD WINAPI Fun1Proc(
  LPVOID lpParameter   // thread data
)
{
    /*while(index++<1000)
        cout<<"thread1 is running"<<endl;*/
    
    //while循环是为了不断的销售火车票。
    //如果不加循环,当卖出一张票之后,线程函数Fun1Proc执行完成,
    //这个线程也就退出了。
    while(TRUE)
    {
        //ReleaseMutex(hMutex);
        //WaitForSingleObject(hMutex,INFINITE);
        //如果还有票,线程1就继续执行
        {
            if(tickets>0) 
            {
                Sleep(1);
                cout<<"thread1 sell ticket : "<<tickets--<<endl;
            }
            else
                break;
        }
        //ReleaseMutex(hMutex);
    }

    /*WaitForSingleObject(hMutex,INFINITE);
    cout<<"thread1 is running"<<endl;*/
    return 0;
}

DWORD WINAPI Fun2Proc(
  LPVOID lpParameter   // thread data
)
{
    //while循环是为了不断的销售火车票。
    while(TRUE)
    {
        //ReleaseMutex(hMutex);
        //WaitForSingleObject(hMutex,INFINITE);
        {
            //如果还有票,线程2就继续执行
            if(tickets>0)
            {
                Sleep(1);
                cout<<"thread2 sell ticket : "<<tickets--<<endl;
            }
            else
                break;
        }
        //ReleaseMutex(hMutex);
    }
    //WaitForSingleObject(hMutex,INFINITE);
    //cout<<"thread2 is running"<<endl;
    return 0;
}

 

### 如何确保互斥量在超时后被正确释放 为了确保互斥量 `mutex` 在尝试获取锁的过程中发生超时时能够正确处理并最终被释放,通常有几种方法可以实现这一目标。以下是具体的方法: #### 使用带超时机制的锁定操作 C++标准库提供了带有超时特性的互斥量类,如 `std::timed_mutex` 和 `std::recursive_timed_mutex`。这些类型的互斥量允许调用方指定等待时间,在这段时间内如果未能成功获取锁,则返回失败状态而不阻塞线程。 ```cpp #include <iostream> #include <thread> #include <chrono> #include <mutex> int main() { std::timed_mutex mtx; bool locked = mtx.try_lock_for(std::chrono::seconds(2)); if (locked) { // 成功获得了锁 try { // 执行临界区代码 } catch (...) { // 处理异常情况 } // 确保离开作用域前解锁 mtx.unlock(); } else { // 超时未获得锁 std::cout << "Failed to acquire lock within timeout period." << std::endl; } return 0; } ``` 这种方法通过设置合理的超时期限来防止死锁的发生,并且即使发生了超时也不会影响程序正常运行[^3]。 #### 利用智能指针自动管理资源 另一种更安全的方式是借助 C++ 的 RAII(Resource Acquisition Is Initialization)原则,即使用像 `std::unique_lock` 这样的工具来自动生成和销毁锁对象。当 `std::unique_lock` 析构时会自动释放它所持有的任何锁,从而减少了手动管理的风险。 ```cpp #include <iostream> #include <thread> #include <chrono> #include <mutex> void critical_section_with_timeout(std::timed_mutex& tm, int id) { using namespace std::literals::chrono_literals; std::unique_lock<std::timed_mutex> lck(tm, std::defer_lock); if (!lck.try_lock_for(1s)) { std::cout << "Thread " << id << ": Failed acquiring the mutex\n"; return; } // 锁已持有,执行受保护的操作... std::this_thread::sleep_for(50ms); // 自动释放锁,因为 unique_lock 对象即将超出范围 } int main(){ std::timed_mutex m; const unsigned thread_count = 4u; std::vector<std::jthread> threads; for(unsigned i=0;i<thread_count;++i){ threads.emplace_back(critical_section_with_timeout,std::ref(m),i+1); } for(auto &t : threads){ t.join(); } return 0; } ``` 这种方式不仅简化了代码逻辑,还提高了安全性,因为它能保证无论何时退出临界区域都会正确地释放锁[^5]。 #### 结合条件变量进行复杂控制 有时可能需要更加复杂的同步行为,比如在一个特定条件下才继续执行后续操作。此时可考虑结合条件变量一起工作,以达到更好的效果。不过这已经超出了单纯讨论互斥量超时的问题范畴。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值