成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

震驚:這個 C++11 關鍵字讓多線程不再需要鎖?thread_local 實戰解密 !

開發
今天咱們聊一個看起來很"高大上"但其實超實用的 C++11 特性:thread_local關鍵字。

今天咱們聊一個看起來很"高大上"但其實超實用的 C++11 特性:thread_local關鍵字。我敢說,這可能是你寫多線程程序時最容易忽略,卻能一秒解決大麻煩的小技巧!

從一個真實的"故事"說起

前幾天一個 C++ 初學者求助我:"我寫的多線程程序結果總是錯的,找不到錯誤原因?"

我一看他貼出的代碼,立馬明白了問題所在:

// 全局變量,所有線程共享
int counter = 0;

void worker_function() {
    // 每個線程增加計數器100000次
    for (int i = 0; i < 100000; ++i) {
        counter++;  // 災難發生的地方!
    }
}

int main() {
    std::thread t1(worker_function);
    std::thread t2(worker_function);

    t1.join();
    t2.join();

    std::cout << "最終計數: " << counter << std::endl;
    // 期望值:200000
    // 實際值:???(遠小于200000)

    return0;
}

這段代碼有什么問題?問題大了去了!多個線程同時讀寫同一個變量counter,沒有任何保護措施,必然導致數據競爭!

他撓撓頭問:"啊?這是什么意思?要怎么解決?加鎖嗎?"

我說:"加鎖當然可以,但是今天我要教你一招更酷的方式 —— thread_local!"

thread_local是什么神仙關鍵字?

簡單來說,thread_local就是告訴編譯器:"嘿,這個變量每個線程要有自己獨立的一份!"

它的特點就是:

  • 每個線程都有這個變量的獨立副本
  • 每個線程只能訪問自己的那份,互不干擾
  • 變量的生命周期與線程一樣長

聽起來是不是很像把變量變成了"個人財產",而不是大家一起"搶"的"公共資源"?

直觀感受:沒有thread_local VS 有thread_local

先看看沒用 thread_local 的情況:

#include <iostream>
#include <thread>
#include <vector>

// 普通全局變量 - 所有線程共享同一份
int global_counter = 0;

void increment_global(int id) {
    for (int i = 0; i < 1000; ++i) {
        global_counter++; // 多線程同時訪問,會出現數據競爭

        // 故意放慢速度,讓競爭更明顯
        if (i % 100 == 0) {
            std::this_thread::sleep_for(std::chrono::milliseconds(10));
        }
    }
    std::cout << "線程 " << id << " 完成,全局計數: " << global_counter << std::endl;
}

int main() {
    std::vector<std::thread> threads;

    for (int i = 0; i < 5; ++i) {
        threads.push_back(std::thread(increment_global, i));
    }

    for (auto& t : threads) {
        t.join();
    }

    std::cout << "最終全局計數: " << global_counter << std::endl;
    // 期望: 5000,實際: 遠小于5000

    return0;
}

運行結果:

線程 3 完成,全局計數: 2986
線程 4 完成,全局計數: 2986
線程 1 完成,全局計數: 2986
線程 0 完成,全局計數: 2986
線程 2 完成,全局計數: 2986
最終全局計數: 2986

看到了嗎?每個線程都增加了1000次,應該是5000,但實際只有2986,丟失了近2000多次增加操作!這就是數據競爭的后果!

再看使用 thread_local 的版本:

#include <iostream>
#include <thread>
#include <vector>

// 全局變量,但使用thread_local修飾
thread_localint local_counter = 0;
// 真正的全局變量,用于匯總
int total_counter = 0;

void increment_local(int id) {
    for (int i = 0; i < 1000; ++i) {
        local_counter++; // 每個線程操作自己的副本,沒有競爭

        // 故意放慢速度
        if (i % 100 == 0) {
            std::this_thread::sleep_for(std::chrono::milliseconds(10));
        }
    }

    // 結束時打印自己的計數值
    std::cout << "線程 " << id << " 完成,局部計數: " << local_counter << std::endl;

    // 安全地將局部計數加到全局總數中(這里仍需要適當的同步,簡化起見省略)
    total_counter += local_counter;
}

int main() {
    std::vector<std::thread> threads;

    for (int i = 0; i < 5; ++i) {
        threads.push_back(std::thread(increment_local, i));
    }

    for (auto& t : threads) {
        t.join();
    }

    std::cout << "最終總計數: " << total_counter << std::endl;
    // 期望: 5000,實際: 就是5000!

    return0;
}

運行結果:

線程 0 完成,局部計數: 1000
線程 2 完成,局部計數: 1000
線程 1 完成,局部計數: 1000
線程 3 完成,局部計數: 1000
線程 4 完成,局部計數: 1000
最終總計數: 5000

完美!每個線程都有自己的local_counter,互不干擾,最后加起來正好5000,一個都不少!

thread_local的內部工作原理是啥?

說到原理,別被嚇著——其實很簡單!

想象一下,如果沒有 thread_local,變量就像一個公共停車位,所有線程都去那停車,必然打架。

而 thread_local 就像是給每個線程都發了一張停車卡,卡上寫著"專屬停車位:XX號"。這樣每個線程都有自己的專屬空間,自然就不會打架了。

技術上講,編譯器會為每個線程分配獨立的存儲空間來存放 thread_local 變量。當線程訪問這個變量時,實際上訪問的是分配給自己的那份副本。

thread_local真實案例:線程安全的單例模式

來看個實用例子,用 thread_local 實現線程安全的單例模式:

#include <iostream>
#include <thread>
#include <string>

class ThreadLogger {
private:
std::string prefix;

// 私有構造函數
ThreadLogger(conststd::string& thread_name) : prefix("[" + thread_name + "]: ") {}

public:
// 獲取當前線程的日志實例
static ThreadLogger& getInstance(const std::string& thread_name) {
    // 每個線程都有自己的logger實例
    thread_local ThreadLogger instance(thread_name);
    return instance;
}

void log(const std::string& message) {
    std::cout << prefix << message << std::endl;
}
};

void worker(const std::string& name) {
    // 獲取當前線程的logger
    auto& logger = ThreadLogger::getInstance(name);

    logger.log("開始工作");
    std::this_thread::sleep_for(std::chrono::milliseconds(200));
    logger.log("工作中...");
    std::this_thread::sleep_for(std::chrono::milliseconds(300));
    logger.log("完成工作");
}

int main() {
    std::thread t1(worker, "線程1");
    std::thread t2(worker, "線程2");
    std::thread t3(worker, "線程3");

    t1.join();
    t2.join();
    t3.join();

    return0;
}

運行結果:

[線程1]: 開始工作
[線程2]: 開始工作
[線程3]: 開始工作
[線程1]: 工作中...
[線程2]: 工作中...
[線程3]: 工作中...
[線程1]: 完成工作
[線程2]: 完成工作
[線程3]: 完成工作

是不是很酷?每個線程都有自己專屬的日志對象,帶有自己的前綴,互不干擾!而且完全不需要加鎖,性能極佳!

thread_local的注意事項

話雖如此,使用 thread_local 也要注意一些坑:

  • 初始化時機:thread_local變量會在線程第一次使用它時初始化,不是在聲明時
  • 內存消耗:每個線程都會分配空間,如果變量很大,多線程環境可能會消耗大量內存
  • 不要濫用:并不是所有共享變量都需要thread_local,有時候簡單的互斥鎖更合適
  • 析構時機:thread_local對象會在線程結束時析構,而不是程序結束時

小結:thread_local到底好在哪?

總結一下 thread_local 的優點:

  • 線程安全:不需要加鎖就能避免數據競爭
  • 性能更好:沒有鎖的開銷,訪問速度更快
  • 代碼簡潔:不需要寫復雜的同步代碼
  • 解決特定問題:某些場景(如線程ID、日志前綴等)用 thread_local 非常合適

最后的"靈魂拷問"

如果我問你:

  • 全局變量是什么?—— 整個程序共享一份
  • 局部變量是什么?—— 每個函數調用有一份
  • 那 thread_local 變量是什么?—— 每個線程有一份!

懂了吧?就是這么簡單!

下次當你看到多線程程序莫名其妙出問題,先想想是不是該用thread_local!一個關鍵字,省下一堆 debug 的時間,何樂而不為?

責任編輯:趙寧寧 來源: 跟著小康學編程
相關推薦

2023-09-22 22:27:54

autoC++11

2023-09-24 13:58:20

C++1auto

2013-05-30 00:49:36

C++11C++條件變量

2025-05-22 09:43:55

2017-05-27 20:59:30

Java多線程synchronize

2009-06-29 18:14:23

Java多線程volatile關鍵字

2013-07-31 11:09:05

C++11

2024-12-18 16:00:00

C++性能優化consteval

2010-03-15 18:11:38

Java多線程

2024-12-24 12:00:00

inlinC++17頭文件

2020-07-17 20:15:03

架構JMMvolatile

2009-09-02 09:24:03

C# this關鍵字

2009-08-21 14:58:56

C# this關鍵字

2009-06-29 18:26:11

Java多線程Synchronize同步類

2019-12-20 15:19:41

Synchroinze線程安全

2024-02-21 20:46:48

C++編程volatile

2009-08-13 13:04:29

C# lock關鍵字

2009-08-06 17:52:23

C#增加that關鍵字

2009-08-13 17:44:34

C# using關鍵字

2009-08-26 15:16:29

C# lock關鍵字
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日韩成人影院 | 一区二区三区在线免费观看视频 | 青草青草久热精品视频在线观看 | 久久99精品国产 | 国产一区精品在线 | 久久6| 成人免费网站www网站高清 | 欧美一级片 | 欧美高清一级片 | 国产亚洲精品久久午夜玫瑰园 | 美女天天操 | 国产乱码精品一区二区三区忘忧草 | 欧美a级成人淫片免费看 | 日韩人体视频 | 成人av片在线观看 | 国产精品免费一区二区三区四区 | 亚洲综合一区二区三区 | 国产欧美精品一区 | 野狼在线社区2017入口 | 乱码av午夜噜噜噜噜动漫 | 在线观看www高清视频 | 国产区在线视频 | 一级片在线观看 | 国产一区h | 久久久久久国产精品免费免费 | 男人天堂网址 | 国产一级在线观看 | 国产精品久久久久久久 | 特黄毛片| 青青草原综合久久大伊人精品 | 最近最新中文字幕 | 亚洲精品一级 | 国产高清在线观看 | 国产精品中文字幕在线观看 | 国产一区在线免费 | 久久av资源网 | xxx视频| 亚洲天堂中文字幕 | 视频三区 | 亚洲欧洲成人av每日更新 | 日韩网站在线 |