首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

C++ 實現類 Java synchronized 的對象級鎖:AALock 設計與實踐

     編輯:關於C++

背景痛點

在多線程環境下,共享數據(如 std::vector、普通數組)的並發訪問需要加鎖保護。傳統做法需為每個共享對象顯式創建 pthread_mutex_t 或 CRITICAL_SECTION,導致:

  • 全局鎖變量泛濫,管理困難
  • 跨文件使用需外部聲明,耦合度高
  • 鎖與對象綁定關係不明確,易出錯

Java/Objective-C 的 synchronized(object) 機制允許直接對任意對象加鎖,極大簡化了同步編程。

AALock 設計思路

核心理念:用一個全局 Map 維護「對象地址 → 互斥鎖」的映射。雖引入查找開銷,但換取使用極致便利:

// aa_lock.h
class AALock {
public:
    explicit AALock(void* object); // 構造時自動加鎖
    ~AALock();                     // 析構時自動解鎖(RAII)
    static void GLock(void* object);   // 靜態手動加鎖
    static void GUnLock(void* object); // 靜態手動解鎖
private:
    void* lock_object_;
};

核心實現細節

// aa_lock.cpp
#include "aa_lock.h"
#include 
#include 

using LockObject = void*;
static std::map gLockMap;
static pthread_mutex_t gMapMutex = PTHREAD_MUTEX_INITIALIZER;

// Map 鎖的初始化/銷毀由靜態對象自動管理
struct AALockInternal {
    AALockInternal()  { pthread_mutex_init(&gMapMutex, NULL); }
    ~AALockInternal() { pthread_mutex_destroy(&gMapMutex); }
} gLockInternal;

AALock::AALock(void* obj) : lock_object_(obj) { GLock(obj); }
AALock::~AALock() { GUnLock(lock_object_); }

void AALock::GLock(void* obj) {
    pthread_mutex_lock(&gMapMutex);
    pthread_mutex_t* mtx;
    auto it = gLockMap.find(obj);
    if (it != gLockMap.end()) {
        mtx = &it->second;
    } else {
        // 新對象:創建鎖並初始化
        pthread_mutex_t new_mtx;
        pthread_mutex_init(&new_mtx, NULL);
        mtx = &gLockMap[obj] = new_mtx;
    }
    pthread_mutex_unlock(&gMapMutex);
    pthread_mutex_lock(mtx); // 加對象鎖
}

void AALock::GUnLock(void* obj) {
    pthread_mutex_lock(&gMapMutex);
    auto it = gLockMap.find(obj);
    pthread_mutex_t* mtx = &it->second;
    pthread_mutex_unlock(&gMapMutex);
    pthread_mutex_unlock(mtx); // 解對象鎖
    // 注意:此處不銷毀鎖,避免重複創建開銷;長期運行可考慮引用計數回收
}

測試驗證:100 線程並發計數與 Vector 操作

// test.cpp
#include 
#include 
#include 
#include "aa_lock.h"

const int MAX_COUNT = 10000;
const int THREAD_NUM = 100;
int64_t gCount = 0;
std::vector gVec;

void* ThreadFunc(void*) {
    for (int i = 0; i < MAX_COUNT; ++i) {
        // 對基本類型加鎖
        AALock::GLock(&gCount);
        ++gCount;
        AALock::GUnLock(&gCount);
        
        // 對 vector 加鎖(非線程安全容器)
        AALock::GLock(&gVec);
        gVec.push_back(i);
        AALock::GUnLock(&gVec);
    }
    return nullptr;
}

int main() {
    pthread_t tids[THREAD_NUM];
    for (int round = 0; round < 10; ++round) {
        gCount = 0; gVec.clear();
        for (int i = 0; i < THREAD_NUM; ++i)
            pthread_create(&tids[i], NULL, ThreadFunc, NULL);
        for (int i = 0; i < THREAD_NUM; ++i)
            pthread_join(tids[i], NULL);
        
        assert(gCount == MAX_COUNT * THREAD_NUM);
        assert(gVec.size() == MAX_COUNT * THREAD_NUM);
    }
    return 0;
}

輸出結果驗證

gCount: 1000000 gVec size: 1000000
... (重複 10 次,無崩潰、無數據競爭) 

優缺點權衡與改進方向

優點缺點/注意事項
使用極簡:AALock lock(obj) 即自動管理Map 查找 + 雙重鎖(Map鎖+對象鎖)有微小性能損耗
無需預聲明鎖變量,天然支持跨模塊共享鎖永不釋放,長期運行大量臨時對象可能泄漏
RAII 保證異常安全僅適用於進程內線程同步,不支持進程間

改進建議:引入引用計數,當對象無鎖持有者且無等待者時延遲銷毀鎖並從 Map 移除;Windows 下可替換為 CRITICAL_SECTION 或 SRWLOCK 提升性能。

總結

AALock 以「約定優於配置」思想,用約 50 行核心代碼實現了類 synchronized 的對象級鎖語義,極大降低了 C++ 多線程同步的認知負擔與代碼雜訊,適合中小型項目快速開發。生產級項目建議根據性能剖析結果決定是否替換為細粒度顯式鎖。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved