1. 程式人生 > >wxwidgets編寫多執行緒程式--wxThread

wxwidgets編寫多執行緒程式--wxThread

細節描述

執行緒基本上來說是應用程式中一條單獨執行的路徑。執行緒有時被稱為輕量級程序,但執行緒與程序的根本不同之處在於不同程序儲存空間是相互獨立的,而同一程序裡的所有執行緒共享同一地址空間。儘管這使得它更容易共享幾個執行緒間的普通資料,但這也使得它有了另一個麻煩,即可能有多個執行緒同時訪問一個變數,所以要小心的使用用於同步物件訪問的變數,例如使用訊號量(mutexes)和關鍵區域(critical sections)是被推薦的。另外,不要建立全域性變數物件,因為在他們的建構函式裡分配空間將會造成記憶體檢查系統的出現問題。

執行緒型別

wxWidgets有兩種型別的執行緒:分離執行緒和聯合執行緒,它們參考了POSIX 執行緒 API。這與win32API不同,其執行緒全部都是聯合的。wxWidgets預設wxThreads為分離執行緒。分離執行緒一旦結束就會刪除它們自己,不論是它們完成處理是自己完成刪除還是通過呼叫Delete()

,分離執行緒必須建立在堆上(例如通過new)。如果你想對你分配的分離執行緒上呼叫函式,你可以儲存它們的例項(這句好像有問題啊,原文:Typically you'llwant to store the instances of the detached wxThreads you allocate, so that youcan call functions on them.)。因為它們的特性所致,你每次訪問它們都必須使用關鍵區域。

//宣告一個新的事件種類用於我們的MyThread類
wxDECLARE_EVENT(wxEVT_COMMAND_MYTHREAD_COMPLETED, wxThreadEvent);
wxDECLARE_EVENT(wxEVT_COMMAND_MYTHREAD_UPDATE, wxThreadEvent);

wxDEFINE_EVENT(wxEVT_COMMAND_MYTHREAD_COMPLETED, wxThreadEvent);//定義事件種類
wxDEFINE_EVENT(wxEVT_COMMAND_MYTHREAD_UPDATE, wxThreadEvent);


class MyFrame;//前置宣告

class MyThread : public wxThread
{
public:
	MyThread(MyFrame *handler)
        	: wxThread(wxTHREAD_DETACHED)
        { 
		m_pHandler = handler 
	}
	
	~MyThread();
protected:
	virtual ExitCode Entry();
	MyFrame *m_pHandler;
};

class MyFrame : public wxFrame
{
public:
	...
	~MyFrame()
	{
	//任何對執行緒的清理相對於在解構函式來說最好在事件處理函式OnClose()中進行。
	//這是因為頂層視窗的事件迴圈在呼叫它的解構函式處不會啟用,如果在視窗析構時執行緒傳送事件,
	//這些事件不會被處理除非你在OnClose結束執行緒
	}
	...
	void DoStartThread();
	void DoPauseThread();
	//執行緒恢復和DoPauseThread()非常相似

	void DoResumeThread() { ... }

	void OnThreadUpdate(wxThreadEvent&);
	void OnThreadCompletion(wxThreadEvent&);
	void OnClose(wxCloseEvent&);
protected:
	MyThread *m_pThread;
	wxCriticalSection m_pThreadCS; // 保護m_pThread指標
	friend class MyThread; //友元函式,允許訪問我們的執行緒m_pThread
	wxDECLARE_EVENT_TABLE();
};

wxBEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_CLOSE(MyFrame::OnClose)
EVT_MENU(Minimal_Start, MyFrame::DoStartThread)
EVT_COMMAND(wxID_ANY, wxEVT_COMMAND_MYTHREAD_UPDATE, MyFrame::OnThreadUpdate)
EVT_COMMAND(wxID_ANY, wxEVT_COMMAND_MYTHREAD_COMPLETED, MyFrame::OnThreadCompletion)
wxEND_EVENT_TABLE()


void MyFrame::DoStartThread()
{
	m_pThread = new MyThread(this);
	if ( m_pThread->Run() != wxTHREAD_NO_ERROR )
	{
		wxLogError("Can't create the thread!");
		delete m_pThread;
		m_pThread = NULL;
	}
	//在呼叫wxThread::Run()之後,指標m_pThread是不安全的:
	//在任何時候執行緒都有可能結束(因為它完成了自己的工作)
	//為了避免呼叫無效的指標,線上程結束時OnThreadExit()中將會把指標賦值為空。
}
wxThread::ExitCode MyThread::Entry()
{
	while (!TestDestroy())
	{
		// ... 幹一些事情...
		wxQueueEvent(m_pHandler, new wxThreadEvent(wxEVT_COMMAND_MYTHREAD_UPDATE));//傳送事件
	}

	//通知事件控制代碼這個執行緒將會被銷燬。注意:這裡我們假定使用m_pHandler是安全的
	//(在這種情況下這將由MyFrame的解構函式確保)
	wxQueueEvent(m_pHandler, new wxThreadEvent(wxEVT_COMMAND_MYTHREAD_COMPLETED));//傳送事件
	return (wxThread::ExitCode)0; // 成功
}

MyThread::~MyThread()
{
	wxCriticalSectionLocker enter(m_pHandler->m_pThreadCS);
	//執行緒正在被銷燬,確保不要呼叫了無效的指標
	m_pHandler->m_pThread = NULL;
}

void MyFrame::OnThreadCompletion(wxThreadEvent&)
{
	wxMessageOutputDebug().Printf("MYFRAME: MyThread exited!\n");
}

void MyFrame::OnThreadUpdate(wxThreadEvent&)
{
	wxMessageOutputDebug().Printf("MYFRAME: MyThread update...\n");
}

void MyFrame::DoPauseThread()
{

	//任何時候我們訪問m_pThread時必須先確認在此期間它不會被修改;由於一個單獨執行緒在給出時位於一個
	//安全區域,所以下面的程式碼是安全的。
	wxCriticalSectionLocker enter(m_pThreadCS);
	if (m_pThread) // 執行緒仍舊存在?
	{
	//不在安全區域,一旦到達這裡,下列情況可能會發生:系統排程把控制權給MyThread::Entry(),
	//而這時候執行緒可能會因為完成了處理而使指標無效

	if (m_pThread->Pause() != wxTHREAD_NO_ERROR )

	wxLogError("Can't pause the thread!");
	}
}

void MyFrame::OnClose(wxCloseEvent&)
{
	{
		wxCriticalSectionLocker enter(m_pThreadCS);
		if (m_pThread) // 執行緒仍舊存在?
			{
				wxMessageOutputDebug().Printf("MYFRAME: deleting thread");
				if (m_pThread->Delete() != wxTHREAD_NO_ERROR )
				wxLogError("Can't delete the thread!");
			}
	}
	//離開安全區域來給執行緒進入解構函式的可能(安全區域保護m_pThreadCS)
	while (1)
	{
		{ // 解構函式執行了嗎?
		wxCriticalSectionLocker enter(m_pThreadCS);
		if (!m_pThread) break;
		}
		// wait for thread completion
		wxThread::This()->Sleep(1);
	}
	Destroy();
}

相反的,聯合執行緒不會自我刪除當他們完成處理,它可以安全建立在棧上。聯合執行緒同樣提供了通過Wait()來獲得Entry()返回值的功能。你不需要急著把所有的執行緒都建立為聯合執行緒,因為它們也擁有不利之處:你必須使用Wait()函式來給聯合執行緒釋放資源,不然它佔用的系統資源不會被釋放,而且你必須手動的正確的刪除執行緒物件如果你沒在棧上建立它。相反的,分離執行緒是“點火即忘”:你只需要開始分離執行緒,當它完成處理,它會自動停止並銷燬它自己

執行緒刪除

不管它是否已經停止,你都應該在聯合執行緒呼叫Wait()來釋放記憶體,就像前面執行緒種類裡說的那樣。如果你在堆上建立了一個執行緒,記得手動刪除它們使用delete操作或類似的只有分離執行緒處理這種記憶體管理型別(後半句好奇怪,原文:If you created ajoinable thread on the heap, remember to delete it manually with thedelete

operator or similar means as onlydetached threads handle this type of memory management.)

因為分離執行緒完成處理會自我刪除,你要小心在其上呼叫程式。如果你確定執行緒正在執行,並想結束它,你可以優雅的呼叫來Delete()結束他(這意味著執行緒會在呼叫Delete()後刪除掉)。這意味著你永遠都不應該嘗試使用delete或相似的操作來刪除分離執行緒。

(這句也有問題,原文:They do this by waiting until the thread in questioncallsTestDestroy() or endsprocessing)

萬不得已你可以使用Kill()立即結束執行緒。這種方式極度不推薦你用,因為這樣並不能釋放與物件相聯絡的資源(儘管分離執行緒的執行緒物件仍會被刪除)並會是c執行庫處於不安全狀態。

 第二執行緒呼叫繪圖wxwidgets

除了“主程式執行緒”(執行wxApp:OnInit()或主函式執行的一個函式)之外的所有執行緒都被認為是“二級執行緒”。

GUI呼叫,例如對wxWindow或wxBitmap的呼叫,在二級執行緒中是不安全的,可能會過早結束你的應用程式。這是由於好幾個原因:包括底層的nativeAPI,類似於其他api如MFC一樣,wxThread不在二級執行緒執行aGUI事件迴圈。

工作區的一些wxWidgets埠會在任何GUI呼叫前呼叫 wxMutexGUIEnter() ,然後呼叫wxMutexGUILeave()。但是,推薦的方法是通過wxQueueEvent()傳送的事件,在主執行緒中簡單地處理GUI呼叫。但這並不代表呼叫這些類是執行緒安全的,包括 wxString在內許多類都不是執行緒安全的。

 不要輪詢wxThread

使用者使用wxThread的一個普遍問題是在主執行緒它們會每次呼叫IsRunning()檢查執行緒看他們是否已經結束,結果發現它們的應用程式出現問題了,因為執行緒是預設的分離執行緒而且執行緒已經自我刪除。自然的,它們會嘗試使用聯合執行緒來取代前面的分離特性。然而,輪詢一個來看他們是否已結束通常來說不是個好主意—實際上,如果可能,任何對正在執行的執行緒呼叫的函式都應該避免。相反的,當執行緒已經結束尋找一種方法來通知你自己。

通常你只需要通知主執行緒,在這種情況你可以通過wxQueueEvent()來發送事件給他。第二執行緒的情況時,如有必要,你可以呼叫別的類的程式當執行緒:完成處理、使用訊號量對變數賦值、別的同步操作

測試圖:


執行時


使用Delete()函式刪除執行緒

我現在感覺聯合執行緒應當是用於當另一執行緒需要等待聯合執行緒完成某項任務時再執行,這時就可以在聯合執行緒週期呼叫TestDesdory()而等待執行緒呼叫聯合執行緒的wait(),這樣就可以避免等待執行緒白白消耗資源。而分離執行緒就是自己執行完自己刪除,如果需要和別的執行緒通訊還可以用事件通知。

用於執行緒同步的物件

1.wxMutex--互斥量

Lock ()
鎖定互斥物件,相當於引數為infinite的LockTimeout() 函式。
注意:若此互斥量早已被呼叫執行緒鎖定,則函式不會阻塞而會立即返回
wxMutexLocker

wxmutex的輔助函式,建構函式中以一個互斥量為引數,他將在解構函式中解鎖互斥量,這使得互斥量的解鎖更加可靠,即使忘記解鎖也不會造成死鎖。

bool wxMutexLocker::IsOk()const

若取得互斥量所有權,返回true,否則返回false.

2.wxCriticalSection--關鍵區域

void Enter ()
進入關鍵區域,如果早已經有別的執行緒進入,則本次呼叫將會被阻塞,直到那個執行緒呼叫了Leave().
注意:如果一個執行緒多次進入關鍵區域,這並不會導致死鎖,事實上在這種情況下函式會立刻返回。
嘗試進入關鍵區域,如果不能進入,它會立即返回false。
void Leave ()
離開關鍵區域使得其他執行緒得以訪問被他保護的全域性資料。
wxCriticalSectionLocker,作用類似wxMutexLocker

3.wxCondition--條件變數

通知所有執行緒,把他們都喚醒
注意:這個函式可能會被呼叫,無論與之相關聯的互斥量是否為鎖定狀態,
bool IsOk () const
若物件早已被成功初始化則返回true,若有錯誤發生返回false
喚醒最多一個物件。
若多個執行緒等待同一條件變數,確切的被喚醒執行緒是未定義的。若無執行緒在等待,這次訊號將會丟失,而條件變數必須再次發訊號,以喚醒那些稍後可能會開始等待的執行緒。
注意:這個函式可能會被呼叫,無論與之相關聯的互斥量是否為鎖定狀態
等待直到條件變數激發。此方法將會自動解鎖與條件變數相關聯的互斥量的鎖。然後使執行緒進入睡眠狀態直到Signal()Broadcast()被呼叫,它會再次鎖定互斥量然後返回。
注意:即使Signal()Wait()之前已經被呼叫,且沒有喚醒任何執行緒,執行緒仍舊會繼續等待下一個訊號,所以確保
Signal()Wait()之後呼叫是很重要的,不然執行緒也許將一直睡眠下去
template<typename Functor >
Wait (const Functor &predicate)
等待直到條件變數發出訊號,且與之關聯的條件為真。這是一個方便的過載用來忽略假的喚醒當等待特定條件變為true時。
這個函式相當於:
while ( !predicate() ){return e;}
等待直到條件被激發或超時時間到達。

4.wxSemaphore--訊號量

wxSemaphore是一個計數器,用於限制併發訪問共享資源的執行緒數。

該計數器始終在0和建立訊號量期間指定的最大值之間。當計數器嚴格大於0時,呼叫wxSemaphore :: Wait()將立即返回並遞減計數器。一旦達到0,任何後續的對wxSemaphore :: Wait的呼叫,只有當訊號量計數器再次變為嚴格的正值時,才會返回,因為呼叫wxSemaphore :: Post會增加計數器的結果。

一般來說,訊號量對於限制只能同時被某些固定數量的客戶端訪問的共享資源的訪問是有用的。例如,當建模酒店預訂系統時,可以建立一個具有等於可用房間總數的計數器的訊號量。每次保留一個房間時,通過呼叫wxSemaphore :: Wait來獲取訊號量,並且每次釋放房間時,都應該通過呼叫wxSemaphore :: Post來釋放訊號量。



相關推薦

wxwidgets編寫執行程式--wxThread

細節描述執行緒基本上來說是應用程式中一條單獨執行的路徑。執行緒有時被稱為輕量級程序,但執行緒與程序的根本不同之處在於不同程序儲存空間是相互獨立的,而同一程序裡的所有執行緒共享同一地址空間。儘管這使得它更容易共享幾個執行緒間的普通資料,但這也使得它有了另一個麻煩,即可能有多個執

使用兩種方式編寫執行程式?

# 方案1 from threading import Thread import time class Sayhi(Thread): def __init__(self,name): super().__init__() self.name=na

使用QtConcurrent編寫執行程式(也可以阻塞)

版權宣告:本文為博主原創文章,未經博主允許不得轉載。 https://blog.csdn.net/Amnes1a/article/details/66470751Qt在其QtConcurrent名稱空間中為我們提供了編寫多執行緒程式的高階API,使用這個API可以使我們在不使用低階的執行緒元素,如互斥鎖,讀寫

ubuntu升級C++11編寫執行程式

最近面試遇到了很多多執行緒問題,我學過java,知道一些多執行緒但是沒有做過大型專案,不瞭解C++多執行緒,我面是C++開發,聽C++可以用很多第三方庫實現多心程比如說boost等,學了一陣子,現在想學習C++11多執行緒,linux自帶的C++版本是4.8.4是支援多執行

使用C++編寫linux執行程式

前言 在這個多核時代,如何充分利用每個 CPU 核心是一個繞不開的話題,從需要為成千上萬的使用者同時提供服務的服務端應用程式,到需要同時開啟十幾個頁面,每個頁面都有幾十上百個連結的 web 瀏覽器應用程式,從保持著幾 t 甚或幾 p 的資料的資料庫系統,到手機上的一個有良好使用者響應能力的 app,為了充分

[C++11 std::thread] 使用C++11 編寫 Linux 執行程式

前言 在這個多核時代,如何充分利用每個 CPU 核心是一個繞不開的話題,從需要為成千上萬的使用者同時提供服務的服務端應用程式,到需要同時開啟十幾個頁面,每個頁面都有幾十上百個連結的 web 瀏覽器應用程式,從保持著幾 t 甚或幾 p 的資料的資料庫系統,到手機上的一個有良好使用者響應能力的 app,為了

linux下C開發執行程式

轉:https://blog.csdn.net/lingfemg721/article/details/6574804   linux下用C開發多執行緒程式,Linux系統下的多執行緒遵循POSIX執行緒介面,稱為pthread。   #

作業系統,核心定時器:使用“訊號”建立一種使用者空間機制來測量一個執行程式執行時間。

      核心是一個作業系統的核心。它負責管理系統的程序、記憶體、裝置驅動程式、檔案和網路系統,決定著系統的效能和穩定性。 定時器是Linux提供的一種定時服務的機制,它在某個特定的時間喚醒某個程序來進行工作。核心在時鐘中斷髮生後檢測各定時器是否到期,在li

java:執行程式的實現方式

1.一種方法是將類宣告為 Thread 的子類。該子類應重寫 Thread 類的 run 方法。 public class Demo2_Thread { public static void main(String[] args) { MyThread mt=new MyThread

JAVA執行程式造成系統時鐘變快

新增jvm引數 註冊為系統服務修改: D:\Tomcat7.0\bin\tomcat7w.exe  在Java面Java Options下最後新增:  -XX:+ForceTimeHighResolution  ---------------------

對於執行程式,單核cpu與核cpu是怎麼工作的

此文中的大部分資料來自於網路上,我只是覺得把有道理的整理一下,方便以後查閱。 1.多執行緒在單核和多核CPU上的執行效率問題的討論a1: 多執行緒在單cpu中其實也是順序執行的,不過系統可以幫你切換那個執行而已,其實並沒有快(反而慢)多個cpu的話就可以在兩個cpu中同時執行了.....

第一個執行程式

#include<windows.h> #include <iostream> DWORD WINAPI fun1Proc( LPVOID lpParameter //thread data ); DWORD WINAPI fun2

解決執行程式使用JDBC連線資料庫的異常

多執行緒就帶來了高併發,短時間內大量的請求發向資料庫,在執行過程中出現了以下錯誤: ** BEGIN NESTED EXCEPTION ** com.mysql.jdbc.CommunicationsException MESSAGE: Communi

ctrl+c退出python執行程式

多工並行處理多數需要用到多執行緒,第一次用python寫一個任務,需要同時監控兩個狀態,就使用了下多執行緒,但測試時候ctrl+c居然退不出,我以為是bug,結果看了下確實是這樣的。如果一個python程式用了多執行緒,當子執行緒沒有結束時,用ctrl+c是關閉不了主執行緒的,這時候就只能用

漫談c++11 Thread庫之使寫執行程式

      c++11中最重要的特性之一就是對多執行緒的支援了,然而《c++ primer》5th卻沒有這部分內容的介紹,著實人有點遺憾。在網上了解到了一些關於thread庫的內容。這是幾個比較不錯的學習thread庫的資源: 前兩個網站我還是非常喜歡的,都是線上的幫助手冊,兩個選擇其中一個就可以了,看

關於執行程式中使用volatile關鍵字的一個小例子

在公司分配給我的爬蟲任務中,具體的資訊又寫需要在詳情頁中取得,所以需要在加入待抓取連結 我們用的框架是基於java 的webmagic ,這個框架可以在啟動時設定多個執行緒抓取,所以待抓取的多個連結可能是跑在不同執行緒上的,但是最後需要統計,一共抓取了多少條資訊,這就需要執行緒同步了。

執行程式評測工具--Intel Vtune 安裝及使用

VTune Amplifier XE Tutorials,即為VTune     一、Amplifer XE能做什麼?  VTune Amplifier XE 可以幫助你分析演算法選擇,標識出你的應用程式怎樣更好的利用可 用的硬體資源。使用VTune Amplifier XE 可以定位或者決定如下內容:  1

java執行程式效能調優 優化過程

我, 一多年c++開發,由於專案原因需要對一個性能底下的多執行緒java程式進行調優,百度google了幾把,媽蛋,沒有發現指導如何java執行緒調優的文章啊,都是一些java使用規範,我去,那我大java的開發工程師都是怎麼調優的啊, 那我大C++工程師就帶領大家如何j

為什麼linux下執行程式如此消耗虛擬記憶體

最近遊戲已上線運營,進行伺服器記憶體優化,發現一個非常奇妙的問題,我們的認證伺服器(AuthServer)負責跟第三方渠道SDK打交道(登陸和充值),由於採用了curl阻塞的方式,所以這裡開了128個執行緒,奇怪的是每次剛啟動的時候佔用的虛擬記憶體在2.3G,然後每次處理訊息就增加64M,

Java執行程式非阻塞式鎖定實現

           Java對多執行緒程式的鎖定已經有良好的支援,通常使用synchronized修飾一個方法或者一段程式碼。但是有一個問題,多個執行緒同時呼叫同一個方法的時候,所有執行緒都被排隊處理了。該被呼叫的方法越耗時,執行緒越多的時候,等待的執行緒等待的時間也就越