1. 程式人生 > >【Boost】boost庫中thread多執行緒詳解1

【Boost】boost庫中thread多執行緒詳解1

1. 概述

執行緒就是,在同一程式同一時間內允許執行不同函式的離散處理佇列。 這使得一個長時間去進行某種特殊運算的函式在執行時不阻礙其他的函式變得十分重要。 執行緒實際上允許同時執行兩種函式,而這兩個函式不必相互等待。

一旦一個應用程式啟動,它僅包含一個預設執行緒。 此執行緒執行main() 函式。 在main()中被呼叫的函式則按這個執行緒的上下文順序地執行。 這樣的程式稱為單執行緒程式。

反之,那些建立新的執行緒的程式就是多執行緒程式。 他們不僅可以在同一時間執行多個函式,而且這在如今多核盛行的時代顯得尤為重要。 既然多核允許同時執行多個函式,這就使得對開發人員相應地使用這種處理能力提出了要求。 然而執行緒一直被用來當併發地執行多個函式,開發人員現在不得不仔細地構建應用來支援這種併發。 多執行緒程式設計知識也因此在多核系統時代變得越來越重要。

2. 執行緒管理

2.1 情景1(test_thread_wait1)

在這個庫最重要的一個類就是boost::thread,它是在boost/thread.hpp裡定義的,用來建立一個新執行緒。下面的示例來說明如何運用它。

新建執行緒裡執行的那個函式的名稱被傳遞到boost::thread的建構函式。 一旦上述示例中的變數t 被建立,該 thread() 函式就在其所線上程中被立即執行。 同時在test_thread_wait1()裡也併發地執行該 threadfun1() 。

為了防止程式終止,就需要對新建執行緒呼叫join() 方法。join() 方法是一個阻塞呼叫:它可以暫停當前執行緒,直到呼叫 join() 的執行緒執行結束。這就使得test_thread_wait1()函式一直會等待到 threadfun1()執行結束。

正如在上面的例子中看到,一個特定的執行緒可以通過諸如t的變數訪問,通過這個變數等待著它的使用 join() 方法終止。 但是,即使 t 越界或者析構了,該執行緒也將繼續執行。 一個執行緒總是在一開始就繫結到一個型別為 boost::thread 的變數,但是一旦建立,就不在取決於它。 甚至還存在著一個叫detach()的方法,允許型別為boost::thread 的變數從它對應的執行緒裡分離。 當然了,像join()的方法之後也就不能被呼叫,因為這個變數不再是一個有效的執行緒。

任何一個函式內可以做的事情也可以在一個執行緒內完成。 歸根結底,一個執行緒只不過是一個函式,除了它是同時執行的。 在上述例子中,使用一個迴圈把5個數字寫入標準輸出流。 為了減緩輸出,每一個迴圈中呼叫wait() 函式讓執行延遲了一秒。 wait() 可以呼叫一個名為sleep() 的函式,這個函式也來自於 Boost.Thread,位於 boost::this_thread 名空間內。

sleep() 要麼在預計的一段時間或一個特定的時間點後時才讓執行緒繼續執行。 通過傳遞一個型別為boost::posix_time::seconds 的物件,在這個例子裡我們指定了一段時間。 boost::posix_time::seconds 來自於Boost.DateTime庫,它被 Boost.Thread 用來管理和處理時間的資料。

雖然前面的例子說明了如何等待一個不同的執行緒,但下面的例子演示瞭如何通過所謂的中斷點讓一個執行緒中斷。

2.2
情景2(test_thread_wait2())

在一個執行緒物件上呼叫 interrupt() 會中斷相應的執行緒。在這方面,中斷意味著一個型別為boost::thread_interrupted的異常,它會在這個執行緒中丟擲。然後這隻有線上程達到中斷點時才會發生。

如果給定的執行緒不包含任何中斷點,簡單呼叫interrupt() 就不會起作用。每當一個執行緒中斷點,它就會檢查interrupt() 是否被呼叫過。只有被呼叫過了, boost::thread_interrupted 異常才會相應地丟擲。

Boost.Thread定義了一系列的中斷點,例如sleep()函式。由於sleep()在這個例子裡被呼叫了五次,該執行緒就檢查了五次它是否應該被中斷。然而sleep()之間的呼叫,卻不能使執行緒中斷。

一旦該程式被執行,它只會列印三個數字到標準輸出流。這是由於在test_thread_wait2()裡3秒後呼叫 interrupt()方法。因此,相應的執行緒被中斷,並丟擲一個boost::thread_interrupted 異常。 這個異常線上程內也被正確地捕獲,catch處理雖然是空的。由於thread() 函式在處理程式後返回,執行緒也被終止。這反過來也將終止整個程式,因為test_thread_wait2()等待該執行緒使用join()終止該執行緒。

Boost.Thread定義包括上述 sleep()函式十個中斷。有了這些中斷點,執行緒可以很容易及時中斷。然而,他們並不總是最佳的選擇,因為中斷點必須事前讀入以檢查boost::thread_interrupted異常。

3
.示例

void wait(int seconds)
{
	boost::this_thread::sleep(boost::posix_time::seconds(seconds));
}

void threadfun1()
{
	for (int i = 0; i < 5; ++i)
	{
		wait(1);
		PRINT_DEBUG(i);
	}
}

void threadfun2() 
{
	try
	{
		for (int i = 0; i < 5; ++i)
		{
			wait(1);
			PRINT_DEBUG(i);
		}
	}
	catch (boost::thread_interrupted&)
	{
		PRINT_DEBUG("thread_interrupted");
	}
}

void test_thread_wait1()
{
	boost::thread t(&threadfun1);
	// join()方法是一個阻塞呼叫:它可以暫停當前執行緒,直到呼叫join()的執行緒執行結束。
	t.join();
}

void test_thread_wait2()
{
	boost::thread t(&threadfun2);
	wait(3);
	t.interrupt();
	t.join();
}

void test_thread_wait3()
{
    boost::thread t(&threadfun2);
    // timed_join()方法同樣也是一個阻塞呼叫:它可以暫停當前執行緒,
    // 直到呼叫join()的執行緒執行結束或者超時
    t.timed_join(boost::posix_time::seconds(3));
}

void test_thread_wait4()
{
    boost::thread t(&threadfun2);
    wait(3);
    // 當thread 與執行緒執行體分離時,執行緒執行體將不受影響地繼續執行,
    // 直到執行結束,或者隨主執行緒一起結束。
    t.detach();
    // 此時join無作用
    t.join();
    // t不再標識任何執行緒 {Not-any-thread}
    assert(t.get_id() == boost::thread::id());
}