多線程的使用方式

1 創建線程

這裏我們直接使用C++11提供的庫函數來進行實現。

簡單示例代碼如下:

#include<iostream>
#include<thread>
using namespace std;

void workFun()
{
	for (int n = 0; n < 4; n++)
		cout << "Hello,other thread." << endl;
}//搶佔式

int main()
{
	thread t(workFun);
	t.detach();
	//t.join();
	for (int n = 0; n < 4; n++)
		cout << "Hello,main thread." << endl;
	while (true)
	{

	}
	return 0;
}

需要注意的幾個點:

  • main線程結束,整個進程執行結束,其它附屬線程也隨之結束。
  • 使用join()的話,主線程會等其它線程執行完才繼續執行;而使用detach()則並行執行。

2 傳遞參數給線程入口函數

測試代碼如下:

#include<iostream>
#include<thread>
using namespace std;

void workFun(int index)
{
	for (int n = 0; n < 4; n++)
		cout << index << "Hello,other thread." << endl;
}//搶佔式

int main()
{
	thread t[4];
	for (int n = 0; n < 4; n++)
	{
		t[n] = thread(workFun,n);
	}
	for (int n = 0; n < 4; n++)
	{
		t[n].join();
		//t[n].detach();
	}

	for (int n = 0; n < 4; n++)
		cout << "Hello,main thread." << endl;
	while (true)
	{

	}
	return 0;
}

對於線程數組來說,我們使用join各個線程之間是可以並行運行的。如果有多個線程對象,我們只調用了一個線程對象的join方法,那麼所有的線程都會以join的方式執行,就表現爲並行執行。但是,在程序執行結束前所有的線程對象都需要調用一次join方法(只能調用一次),否則程序會出現異常。


3 鎖與臨界區

在上面的代碼中我們多個線程中,cout屬於共享資源,在輸出的時候很容易出問題。我們這裏使用一下鎖,保證共享資源的安全性。代碼如下:

#include<iostream>
#include<thread>
using namespace std;

void workFun(int index)
{
	for (int n = 0; n < 4; n++)
		cout << index << "Hello,other thread." << endl;
}//搶佔式

int main()
{
	thread t[4];
	for (int n = 0; n < 4; n++)
	{
		t[n] = thread(workFun,n);
	}
	for (int n = 0; n < 4; n++)
	{
		t[n].join();
		//t[n].detach();
	}

	for (int n = 0; n < 4; n++)
	{
		//臨界區域-開始
		m.lock();
		cout << "Hello,main thread." << endl;
		m.unlock();
		//臨界區域-結束
	}
		
	while (true)
	{

	}
	return 0;
}

4 自解鎖

爲了防止上鎖後沒解鎖,於是誕生了自解鎖,原理和智能指針類似。

示例代碼:

mutex m;

int sum = 0;
void workFun(int index)
{
	for (int n = 0; n < 20000000; n++)
	{
		//自解鎖
		lock_guard<mutex> lg(m);
		//臨界區域-開始
		//m.lock();
		sum++;
		//m.unlock();
		//臨界區域-結束
	}
}//搶佔式

自解鎖源碼:

// CLASS TEMPLATE lock_guard
template <class _Mutex>
class lock_guard { // class with destructor that unlocks a mutex
public:
    using mutex_type = _Mutex;

    explicit lock_guard(_Mutex& _Mtx) : _MyMutex(_Mtx) { // construct and lock
        _MyMutex.lock();
    }

    lock_guard(_Mutex& _Mtx, adopt_lock_t) : _MyMutex(_Mtx) { // construct but don't lock
    }

    ~lock_guard() noexcept {
        _MyMutex.unlock();
    }

    lock_guard(const lock_guard&) = delete;
    lock_guard& operator=(const lock_guard&) = delete;

private:
    _Mutex& _MyMutex;
};

5 原子操作

對於一些基本類型,我們可以將其定義爲原子類型,避免作爲共享資源運算時需要使用鎖。原子類型相對於鎖,性能有很大的提升。

示例代碼如下:

#include<iostream>
#include<thread>
#include<mutex>//鎖
#include<atomic>//原子
#include"CELLTimestamp.hpp"
using namespace std;
//原子操作   原子 分子 
mutex m;
const int tCount = 4;
atomic_int sum = 0;
void workFun(int index)
{
	for (int n = 0; n < 20000000; n++)
	{
		//自解鎖
		//lock_guard<mutex> lg(m);
		//臨界區域-開始
		//m.lock();
		sum++;
		//m.unlock();
		//臨界區域-結束
	}//線程安全 線程不安全
	//原子操作 計算機處理命令時最小的操作單位
	//cout << index << "Hello,main thread." << n << endl;
}//搶佔式

int main()
{
	thread t[tCount];
	for (int n = 0; n < tCount; n++)
	{
		t[n] = thread(workFun, n);
	}
	CELLTimestamp tTime;
	for (int n = 0; n < tCount; n++)
	{
		t[n].join();
		//t[n].detach();
	}
	cout << tTime.getElapsedTimeInMilliSec() << ",sum=" << sum << endl;
	sum = 0;
	tTime.update();
	for (int n = 0; n < 80000000; n++)
	{
		sum++;
	}
	cout << tTime.getElapsedTimeInMilliSec() << ",sum=" << sum << endl;
	cout << "Hello,main thread." << endl;
	return 0;
}

參考資料:

  1. C++ 百萬併發網絡通信引擎架構與實現 (服務端、客戶端、跨平臺) Version 1.0
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章