C++11: std::thread和std::this_thread

C++11起,標準庫除了提供std::async(),這樣的高級線程接口之外,還提供了更加簡單的std::thread,咱們只須要聲明一個std::thread對象,而後傳遞進去函數(function注意這裏並非callable object)進去,以及該function可接受的參數,而後要麼等待它結束,要麼將他卸離(detach).java

若是std::thread想要使用 callable object須要配合std::packaged_task.ios

咱們能夠看一下std::thread對傳入的function的調用:dom

template<typename Func, typename ...Types,
                        typename = typename std::enable_if<
                                                         !std::is_member_pointer<typename std::decay<Func>::type>::value,
						          void>::type>
auto invoke(Func&& func, Types&&... args)->decltype((std::forward<Func>(func))(std::forward<Types>(args)...))
{
	return (std::forward<Func>(func))(std::forward<Types>(args)...);
}

 

首先來看一個例子:async

#include <iostream>
#include <thread>
#include <chrono>
#include <random>
#include <exception>

void doSomething(const int& number, const char& c)
{
	try {
		std::default_random_engine engine(42 * static_cast<int>(c));
		std::uniform_int_distribution<int> distribution(10, 100);

		for (int i = 0; i < number; ++i) {
			std::this_thread::sleep_for(std::chrono::milliseconds(distribution(engine)));
			std::cout.put(c).flush();
		}

	}catch (const std::exception& e) {
		std::cerr << "THREAD-EXCEPTION (thread " << std::this_thread::get_id() << "): " << e.what() << std::endl;

	}catch (...) {
		std::cerr << "THREAD-EXCEPTION (thread " << std::this_thread::get_id() << ")" << std::endl;
	}
}

int main()
{
	try {
		std::thread t1(doSomething, 5, '.');
		std::cout << "- started fg thread " << t1.get_id() << std::endl;

		for (int i = 0; i < 5; ++i) {
			std::thread temp_thread(doSomething, 10, 'a' + i);
			std::cout << "-detach started thread bg thread " << temp_thread.get_id() << std::endl;
			temp_thread.detach();
		}

		std::cin.get();
		std::cout << "- join fg thread " << t1.get_id() << std::endl;
		t1.join();

	}catch (const std::exception& e) {
		std::cerr << "EXCEPTION: " << e.what() << std::endl;
	}

	return 0;
}

std::thread的構造函數:函數

thread() noexcept;

template <class Fn, class... Args>
explicit thread (Fn&& fn, Args&&... args);

thread (const thread&) = delete;

thread (thread&& x) noexcept;

1,默認構造函數,構建一個沒有任何callable object對象的線程.this

2,顯式構造函數(也就意味着不支持隱式的類型轉換),接受一個function以及該function可接受的參數(注意這些參數都是by-value的形式傳遞進去的,也就是拷貝).atom

3,被刪除了的copy-constructor,也就是說std::thread是不支持copy的.spa

4,移動構造函數,被移動的std::thread處於無效狀態,當前std::thread得到被移動對象的callable object以及callable object可接受的參數.線程

std::thread::detachcode

調用該函數使得當前std::thread對象所與母體分離(detach),也就是說使得當前std::thread運行於後臺不受任何控制(這樣也隨之帶來一個問題,可能main線程都結束了該線程還在運行).

void detach();

std::thread::get_id

1,若是該std::thread是joinable狀態(joinable狀態後面會提到),那麼就返回一個獨一無二的(unique)的當前std::thread的id(std::thread::id).

2,若是該std::thread是not joinable狀態,返回std::thread::id();

#include <iostream>
#include <thread>
#include <chrono>

std::thread::id main_thread_id = std::this_thread::get_id();

void is_main_thread()
{
	if (main_thread_id == std::this_thread::get_id()) {
		std::cout << "main-thread!" << std::endl;

	}else {
		std::cout << "not main thread! " << std::endl;
	}
}

int main()
{
	is_main_thread();
	std::thread other_thread(is_main_thread);
	other_thread.join();

	return 0;
}

std::thread::joinable

該函數返回一個bool值:

1,若是當前std::thread對象是default-constructor構造出來的返回false.

2,若是當前std::thread對象被移動到了其餘std::thread對象返回false.

3,若是當前std::thread對象的detach()和join()被調用過了返回false.

bool joinable() const noexcept;

std::thread::join

block(阻塞)調用join()的線程,直到std::thread所在的線程完成與此同時std::thread獨顯被設置爲not joinable.

void join();

std::thread::operator=

std::thread仍然是不支持copy-assign-operator(拷貝賦值運算符),可是支持move-assign-operator.

對於move-assign-operator須要注意的是:

1,噹噹前std::thread對象處於joinable狀態的時候對當前對象調用move-assign-operator,會terminal.

2,若是當前std::thread對象處於not joinable狀態那麼OK.

thread& operator= (thread&& rhs) noexcept;
	
thread& operator= (const thread&) = delete;

------------------------------我是分割線----------------------------------

std::this_thread其中的this_thread是位於std這個命名空間中的命名空間.位於該命名空間中有幾個函數.這些函數通常都是用來輔助std::thread,std::async.

std::this_thread::get_id

返回一個獨一無二的當前線程的ID(通常也就是unsigned int類型).

thread::id get_id() noexcept;

std::this_thread::sleep_for

阻塞(block)正在調用該函數的線程一段時間.

template <class Rep, class Period>
  void sleep_for (const chrono::duration<Rep,Period>& rel_time);

std::this_thread::sleep_until

阻塞(block)正在調用該函數的線程直到指定的時間點(timepoint).

template <class Rep, class Period>
  void sleep_for (const chrono::duration<Rep,Period>& rel_time);

std::this_thread::yield

這個是個重點,能夠參考java和PHP的該函數.

該函數的主要做用是:使正在處於運行狀態的該線程,回到可運行狀態,以容許其餘具備相同優先級的線程得到執行的機會。可是頗有可能該線程剛剛回到可執行狀態又被再次執行。

void yield() noexcept;
#include <iostream>
#include <thread>
#include <chrono>
#include <atomic>

std::atomic<bool> boolean(false);

void  doSomething(const int& id)
{
	while (!boolean) {
		std::this_thread::yield();//注意這裏.
	}

	for (int i = 0; i < 1000000; ++i) {
		;
	}

	std::cout << id;

}

int main()
{
	std::thread threads[10];

	for (unsigned int i = 0; i < 10; ++i) {
		threads[i] = std::thread(doSomething, i);
	}

	boolean = true;
	for (std::thread& ref_thread : threads) {
		ref_thread.join();
	}

	std::cout << '\n';

	return 0;
}
相關文章
相關標籤/搜索