Linux下c++ 多線程相關(thread, mutex, atomic消息隊列)


環境

  • wsl ubuntu 18.04 LTS
  • gcc version 7.5.0

其實這個並不重要,就圖個儀式感,hh。不過必須是在Linux系統下實現的,windows平台是不可以的,c++在windows平台實現多線程不是使用的這個庫

時間片輪轉

代碼

#include <iostream>
#include <thread>

using namespace std;

void func(int i,int times){
    puts("thread id: ");
    for(int i=0;i<=times;i++)
        printf("%d ",i);
    cout<<endl;
}

int main() {
    thread th[5];

    for(int i=0;i<5;i++)
        th[i]=thread(func,i,40);// 這里的times參數最好大一點,才能看出效果
    // thread 傳入的參數為:函數指針,函數的各個參數
    for(int i=0;i<10;i++)
        th[i].join();
    return 0;
}

編譯

g++ main.cpp -o main -lpthread #這里的 -lpthread 是鏈接thread庫,很重要,不添加的話會編譯不通過

這樣重復運行程序,會發現每次的輸出不一樣。這就是不同線程時間片輪轉的結果

線程同步

代碼

#include <iostream>
#include <thread>

using namespace std;

int n;

void func() {
	for (int i = 0; i < 10000; i++)
		n++;
}
int main() {
	thread th[100];

	for (thread &it : th)
		it = thread(func);

	for (thread &it : th)
		it.join();

	cout << n << endl;

	return 0;
}

按照邏輯應該輸出 1000000,但是實際上並沒有,往往小於此值。因為各個線程出現了同時訪問n的情況,所以針對這種情況,我們需要用到互斥鎖

為什么不能使用 std::atomic?

mutex庫中常用的std::mutexstd::atomic都可實現互斥訪問,我們常常為了追求更高的效率,會用std::atomic而不是std::mutex,並且std::atomic的使用更加方便易懂,但是如果我們要用std::atomicstd::queue來實現消息隊列,是不可行的,接下來我會根據我所找到的資料,做一個大致的解釋。

  • 先放一個stackoverflow上大佬的大致解釋

    A) atomic <queue <T>> fifo;

    B) queue <atomic <T>> fifo;

    兩種方式都是不可以的,A甚至不能正確編譯,B可以實現原子操作的讀和寫,但是無法實現queue的例如pop(), push()等操作

  • 首先,atomic<T> var中,T的類型必須是TriviallyCopyable(翻譯過來可以理解成拷貝不變)。那么是TriviallyCopyable呢?文檔如下

    Scalar types標量類型

    • 標量類型(Scalar type)是相對復合類型(Compound type)來說的:標量類型只能有一個值,而復合類型可以包含多個值。復合類型是由標量類型構成的。
    • 在C語言中,整數類型(int、short、long等)、字符類型(char、wchar_t等)、枚舉類型(enum)、小數類型(float、double等)、布爾類型(bool)都屬於標量類型,一份標量類型的數據只能包含一個值
    • 結構體(struct)、數組(array)、字符串(string)都屬於復合類型,一份復合類型的數據可以包含多個標量類型的值,也可以包含其他復合類型的值。
    • rivially copyable classes, i.e. classes satisfying following requirements拷貝不變類,也就是滿足以下條件:

      • At least one copy constructor, move constructor, copy assignment operator, or move assignment operator is eligible必須有一個拷貝構造函數,或者移動構造函數,或者拷貝賦值運算符,或者移動賦值運算符
      • Every eligible copy constructor (if any) is trivial每個復制構造函數均為平凡或棄置的
      • Every eligible move constructor (if any) is trivial每個移動構造函數均為平凡或棄置的
      • Every eligible copy assignment operator (if any) is trivial每個復制賦值運算符均為平凡或棄置的
      • Every eligible move assignment operator (if any) is trivial每個移動賦值運算符均為平凡或棄置的
      • Has a trivial non-deleted destructor平凡而未棄置的析構函數
    • Arrays of TriviallyCopyable objects可平凡復制 (TriviallyCopyable) 對象的數組

      (補充:什么叫平凡類函數呢?簡單點講就是如果類T滿足:1. 函數不是用戶提供的,即他是隱式定義或者預置的;2. T沒有虛成員函數;3. T沒有虛基類;4. 為 T 的每個直接基類選擇的復制構造函數都是平凡的;5. 為 T 的每個類類型(或類類型數組)的非靜態成員選擇的復制構造函數都是平凡的)

所以講了一大堆,就是一個意思,std::atomicstd::queue來實現消息隊列,是不可行的!

實現對queue的操作保護只能是使用mutex!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM