與 C++11 多線程相關的頭文件

C++11 新標準中引入了四個頭文件來支持多線程編程,他們分別是<atomic> ,<thread>,<mutex>,<condition_variable>和<future>。

 

  • <atomic>:該頭文主要聲明瞭兩個類, std::atomic 和 std::atomic_flag,另外還聲明瞭一套 C 風格的原子類型和與 C 兼容的原子操作的函數。
  • <thread>:該頭文件主要聲明瞭 std::thread 類,另外 std::this_thread 命名空間也在該頭文件中。
  • <mutex>:該頭文件主要聲明瞭與互斥量(mutex)相關的類,包括 std::mutex 系列類,std::lock_guard, std::unique_lock, 以及其他的類型和函數。
  • <condition_variable>:該頭文件主要聲明瞭與條件變量相關的類,包括 std::condition_variable 和 std::condition_variable_any。
  • <future>:該頭文件主要聲明瞭 std::promise, std::package_task 兩個 Provider 類,以及 std::future 和 std::shared_future 兩個 Future 類,另外還有一些與之相關的類型和函數,std::async() 函數就聲明在此頭文件中。

 

 

C++11中引入了一個用於多線程操作的thread類,簡單多線程示例:

 

複製代碼
#include <iostream>
#include <thread>
#include <Windows.h>

using namespace std;

void thread01()
{
    for (int i = 0; i < 5; i++)
    {
        cout << "Thread 01 is working !" << endl;
        Sleep(100);
    }
}
void thread02()
{
    for (int i = 0; i < 5; i++)
    {
        cout << "Thread 02 is working !" << endl;
        Sleep(200);
    }
}

int main()
{
    thread task01(thread01);
    thread task02(thread02);
    task01.join();
    task02.join();

    for (int i = 0; i < 5; i++)
    {
        cout << "Main thread is working !" << endl;
        Sleep(200);
    }
    system("pause");
}
複製代碼

 

 

輸出:

 

兩個子線程並行執行,join函數會阻塞主流程,所以子線程都執行完成之後才繼續執行主線程。可以使用detach將子線程從主流程中分離,獨立運行,不會阻塞主線程:

複製代碼
 

#include <iostream>
#include <thread>
#include <Windows.h>

using namespace std;

void thread01()
{
    for (int i = 0; i < 5; i++)
    {
        cout << "Thread 01 is working !" << endl;
        Sleep(100);
    }
}
void thread02()
{
    for (int i = 0; i < 5; i++)
    {
        cout << "Thread 02 is working !" << endl;
        Sleep(200);
    }
}

int main()
{
    thread task01(thread01);
    thread task02(thread02);
    task01.detach();
    task02.detach();

    for (int i = 0; i < 5; i++)
    {
        cout << "Main thread is working !" << endl;
        Sleep(200);
    }
    system("pause");
}
複製代碼
 
輸出:

 

使用detach的主線程和兩個子線程並行執行。

 

帶參子線程

 

在綁定的時候也可以同時給帶參數的線程傳入參數:

複製代碼
 

#include <iostream>
#include <thread>
#include <Windows.h>

using namespace std;

//定義帶參數子線程
void thread01(int num)
{
    for (int i = 0; i < num; i++)
    {
        cout << "Thread 01 is working !" << endl;
        Sleep(100);
    }
}
void thread02(int num)
{
    for (int i = 0; i < num; i++)
    {
        cout << "Thread 02 is working !" << endl;
        Sleep(200);
    }
}

int main()
{
    thread task01(thread01, 5);  //帶參數子線程
    thread task02(thread02, 5);
    task01.detach();
    task02.detach();

    for (int i = 0; i < 5; i++)
    {
        cout << "Main thread is working !" << endl;
        Sleep(200);
    }
    system("pause");
}
複製代碼

輸出跟上例輸出一樣:

 

多線程數據競爭

 

多個線程同時對同一變量進行操作的時候,如果不對變量做一些保護處理,有可能導致處理結果異常:

 

複製代碼
 

#include <iostream>
#include <thread>
#include <Windows.h>

using namespace std;

int totalNum = 100;

void thread01()
{
    while (totalNum > 0)
    {
        cout << totalNum << endl;
        totalNum--;
        Sleep(100);
    }
}
void thread02()
{
    while (totalNum > 0)
    {
        cout << totalNum << endl;
        totalNum--;
        Sleep(100);
    }
}

int main()
{
    thread task01(thread01);
    thread task02(thread02);
    task01.detach();
    task02.detach();
    system("pause");
}
複製代碼

 

輸出結果(部分):

 

 

有兩個問題,一是有很多變量被重複輸出了,而有的變量沒有被輸出;二是正常情況下每個線程輸出的數據後應該緊跟一個換行符,但這裏大部分卻是另一個線程的輸出。

這是由於第一個線程對變量操作的過程中,第二個線程也對同一個變量進行各操作,導致第一個線程處理完後的輸出有可能是線程二操作的結果。針對這種數據競爭的情況,可以使用線程互斥對象mutex保持數據同步。

mutex類的使用需要包含頭文件mutex:

 

複製代碼
#include <iostream>
#include <thread>
#include <Windows.h>
#include <mutex>

using namespace std;

mutex mu;  //線程互斥對象

int totalNum = 100;

void thread01()
{
    while (totalNum > 0)
    {
        mu.lock(); //同步數據鎖
        cout << totalNum << endl;
        totalNum--;
        Sleep(100);
        mu.unlock();  //解除鎖定
    }
}
void thread02()
{
    while (totalNum > 0)
    {
        mu.lock();
        cout << totalNum << endl;
        totalNum--;
        Sleep(100);
        mu.unlock();
    }
}

int main()
{
    thread task01(thread01);
    thread task02(thread02);
    task01.detach();
    task02.detach();
    system("pause");
}
複製代碼

 

多線程中加入mutex互斥對象之後輸出正常:

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章