動態

詳情 返回 返回

多線程安全訪問共享資源(互斥) - 動態 詳情

概念

1.多個執行流進行安全訪問的共享資源——臨界資源
2.多個執行流中,訪問臨界資源的代碼——臨界區--往往是線程代碼的很小一部分
3.想讓多個線程串行訪問共享資源——互斥
4.對一個資源進行訪問的時候,要麼不做,要麼做完——原子性

解決方案:

解決方案:加鎖

互斥鎖pthread_mutex_t確保同一時間只有一個線程能進入臨界區

一、POSIX線程庫(pthread)互斥鎖(Mutex)接口

函數接口 功能描述 參數與返回值
pthread_mutex_init 初始化互斥鎖 - 參數:pthread_mutex_t *mutex(鎖對象)、const pthread_mutexattr_t *attr(屬性,通常為NULL
- 返回值:成功返回0,失敗返回錯誤碼。
pthread_mutex_destroy 銷燬互斥鎖(釋放資源) - 參數:pthread_mutex_t *mutex(已初始化的鎖對象)
- 返回值:成功返回0,失敗返回錯誤碼。
pthread_mutex_lock 加鎖(阻塞式):若鎖已被佔用,當前線程會阻塞等待 - 參數:pthread_mutex_t *mutex
- 返回值:成功返回0,失敗返回錯誤碼(如被信號中斷返回EINTR)。
pthread_mutex_trylock 嘗試加鎖(非阻塞式):若鎖已被佔用,立即返回失敗,不阻塞 - 參數:pthread_mutex_t *mutex
- 返回值:成功返回0,失敗返回EBUSY(鎖被佔用)或其他錯誤碼。
pthread_mutex_unlock 解鎖:釋放鎖,喚醒等待隊列中的一個線程 - 參數:pthread_mutex_t *mutex
- 返回值:成功返回0,失敗返回錯誤碼(如未加鎖時解鎖返回EPERM)。

二、C++標準庫()基礎互斥鎖類

類名 功能描述 核心成員函數
std::mutex 基礎互斥鎖(不可遞歸,同一線程不能重複加鎖) - lock():加鎖(阻塞)
- try_lock():嘗試加鎖(非阻塞,成功返回true
- unlock():解鎖
std::recursive_mutex 遞歸互斥鎖:允許同一線程多次加鎖(需對應次數的解鎖) std::mutex,但支持同一線程重複lock()(次數不超過實現限制)
std::timed_mutex 帶超時的互斥鎖:支持在指定時間內嘗試加鎖 增加try_lock_for(std::chrono::duration)try_lock_until(std::chrono::time_point)

如果鎖是局部的需要用pthread_mutex_destroyint pthread_mutex_init來創建和銷燬,如果是全局或者靜態的,則直接用pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;進行初始化

code:

Mutex.hpp:

#pragma once
#include<pthread.h>
class Mutex{
public:
    Mutex(const pthread_mutex_t &mtx):mtx_(mtx){
        pthread_mutex_lock(&mtx_);
    }
    ~Mutex(){
        pthread_mutex_unlock(&mtx_);
    }
private:
    pthread_mutex_t mtx_;
};

main:

#include<iostream>
#include<vector>
#include<cstdio>
#include<unistd.h>
#include<cassert>
#include "Mutex.hpp"
int tickets=10000;
pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;
class ThreadData{
public:
    pthread_t m_tid;
    char m_buffer[64];
};
void *getTicket(void *args){
    ThreadData* td=static_cast<ThreadData*>(args);
    long long getnum=0;
    while(true){
        {
            Mutex m(mutex);
            usleep(1254);
            if(tickets>0){
                std::cout<<td->m_buffer<<" : 還剩票數 "<<tickets<<std::endl;
                tickets--;
                getnum++;
            }
            else{
                break;
            }
        }
    }
    return (void*)getnum;
}

int main(){
    std::vector<ThreadData*> tds;
#define NUM 10
    for(int i=1;i<=NUM;i++){
        ThreadData *td=new ThreadData;
        snprintf(td->m_buffer,sizeof(td->m_buffer),"thread[%d]",i);
        int n=pthread_create(&td->m_tid,nullptr,getTicket,(void*)td);
        assert(n==0);
        (void)n;
        tds.push_back(std::move(td));
    }
    for(int i=0;i<(int)tds.size();i++){
        long long ret;
        int n=pthread_join(tds[i]->m_tid,(void**)&ret);
        assert(n==0);
        (void)n;
        std::cout<<tds[i]->m_buffer<<"獲得票數:"<<ret<<std::endl;
        delete tds[i];
    }

}

Add a new 評論

Some HTML is okay.