多線程安全訪問共享資源(互斥)
概念
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_destroy與int 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];
}
}

浙公網安備 33010602011771號