国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
漫談C++ Builder多線程編程技術(shù)

漫談C++ Builder多線程編程技術(shù)

  摘 要:本文簡單介紹了Windows環(huán)境下進行多線程編程的意義,重點討論了C++Builder環(huán)境下開發(fā)多線程應(yīng)用程序這一問題,并通過實現(xiàn)生產(chǎn)者-消費者問題,幫我們更好地理解同步概念及其實現(xiàn)方法。
 
  線程之可行性
 
  在很多情況下,可能需要為程序創(chuàng)建線程。這里給出其中一些可能性:
 
 ?。?)如果創(chuàng)建的是一個多文檔接口(Multiple Document Interface,MDI)程序,那么為每個窗口分配一個線程就顯得十分重要了,例如,對于一個通過多個Modem同時連接到多個主機的MDI通信程序而言,如果每個窗口都有它自己的線程來和一個主機通信,那么整個事情就簡化很多。
 
 ?。?)如果使用的是一臺有多個處理器的機器,并希望充分利用所有可能獲得的CPU資源,那么就需要將應(yīng)用程序分解成多個線程。Windows2000中CPU的劃分單位為線程。因此,如果程序只包含一個線程,那么,默認環(huán)境下該程序只能使用其中一個CPU.但是,如果將此程序劃分為多個線程,那么Windows2000就可以在不同的CPU上運行各個線程。
 
 ?。?)在后臺運行的某些任務(wù)的同時,要求用戶還可以繼續(xù)使用應(yīng)用程序進行工作。利用線程很容易實現(xiàn)這點。例如:可以將一些冗長的重算、頁面格式化操作、文件的讀寫等活動都放在單獨的線程中,使其在后臺運行,而不會對用戶造成影響。
 
  同步
 
  撰寫多線程程序的一個最具挑戰(zhàn)性的問題就是:如何讓一個線程和另一個線程合作。這引出了一個非常重要的問題:同步。所謂同步是指進程、線程間相互通信時避免破壞各自數(shù)據(jù)的能力。Windows環(huán)境下的同步問題是由Win32系統(tǒng)的CPU時間片分配方式引起的。雖然在某一時刻,只有一個線程占用CPU(單CPU)時間,但是無法知道在什么時候,在什么地方線程被打斷,這樣如何保證線程之間不破壞彼此的數(shù)據(jù)就顯得格外重要。同步問題是如此重要,也相當有趣,因而吸引了不少學(xué)者對他進行研究,由此產(chǎn)成了一系列經(jīng)典的進程同步問題,其中較有代表性的是"生產(chǎn)者-消費者問題"、"讀者-寫者問題""哲學(xué)家進餐問題"等。在此,本文簡要討論了C++Builder平臺下如何利用多線程編程技術(shù)實現(xiàn)"生產(chǎn)者-消費者"問題,幫助我們更好得理解同步概念及其實現(xiàn)方法。
 
  生產(chǎn)者-消費者問題
 
  生產(chǎn)者-消費者問題是一個著名的進程同步問題。它描述的是:有一群生產(chǎn)者進程在生產(chǎn)消息,并將此消息提供給消費者進程去消費。為使生產(chǎn)者進程和消費者進程能并發(fā)進行,在他們之間設(shè)置了一個具有N個緩沖區(qū)的緩沖池,生產(chǎn)者進程可以將它所生產(chǎn)的消息放入一個緩沖區(qū)中,消費者進程可以從一個緩沖區(qū)中取得一個消息消費。盡管所有的生產(chǎn)者進程和消費者進程都是以異步方式進行的,但他們之間必須保持同步,即不允許消費者進程到一個空的緩沖區(qū)中去取消息,也不允許生產(chǎn)者進程向一個已裝滿消息且尚未被取走消息的緩沖區(qū)中投放消息。
 
  C++Builder多線程應(yīng)用程序編程基礎(chǔ)
 
  1、使用C++Builder提供的TThread類
 
  VCL類庫提供了用于線程編程的TThread類。在TThread類中封裝了Windows中關(guān)于線程機制的WindowSAPI.對于大多數(shù)的應(yīng)用程序來說,可在應(yīng)用程序中使用線程對象來表示執(zhí)行線程。線程對象通過封裝使用線程所需的內(nèi)容,簡化了多線程應(yīng)用程序的編寫。注意,線程對象不允許控制線程堆棧的大小或其安全屬性。若需要控制這些,必須使用WindowsAPI的Create Thread()或Begin Thread()函數(shù)。
 
  TThread類有以下一些屬性和方法:
 1) 屬性:

  ·Priority:優(yōu)先級屬性??梢栽O(shè)置線程的優(yōu)先級。

  ·Return Value:返回值屬性。當線程介紹時返回給其他線程一個數(shù)值。

  ·Suspended:掛起屬性??梢耘袛嗑€程是否被掛起。

  ·Terminated:結(jié)束屬性。用來標志是否應(yīng)該結(jié)束線程。

  ·ThreadID:標識號屬性。在整個系統(tǒng)中線程的標識號。使用Windows API函數(shù)時該屬性非常有用。

  2) 方法:

  ·Do Terminate:產(chǎn)生一個On Terminate事件,但是不結(jié)束線程的執(zhí)行。

  ·Resume:喚醒一個線程繼續(xù)執(zhí)行。

  ·Suspend:掛起一個線程,要與Resume過程成對使用。

  ·Synchronize:由主VCL線程調(diào)用的一個同步過程。

  ·Terminate:將Terminate屬性設(shè)置為True,中止線程的執(zhí)行。

  ·Wait For:等待線程的中止并返回Return Value屬性的數(shù)值。


  2、協(xié)調(diào)線程
 
  在編寫線程執(zhí)行時運行的代碼時,必須考慮到可能同步執(zhí)行的其他線程的行為。特別注意,避免兩個線程試圖同時使用相同的全局對象或變量。另外,一個線程中的代碼會依賴其他線程執(zhí)行任務(wù)的結(jié)果。
 
  1) 避免同時訪問
 
  為避免在訪問全局對象或變量時與其他線程發(fā)生沖突,可能需要暫停其他線程的執(zhí)行,直到該線程代碼完成操作。
 
 ?。?)鎖定對象。一些對象內(nèi)置了鎖定功能,以防止其他線程使用該對象的實例。例如,畫布對象(TCanvas及其派生類)有一種Lock()函數(shù)可以防止其他線程訪問畫布,直到調(diào)用Unlock()函數(shù)。顯然,這種方法只對部分類有效。
 
 ?。?)使用重要區(qū)段。

    若對象沒有提供內(nèi)置的鎖定功能,可使用重要區(qū)段。重要區(qū)段像門一樣,每次只允許一個線程進入,要使用重要區(qū)段,需創(chuàng)建TCriticalSection的全局實例。TCriticalSection有兩個函數(shù):Acquire()(阻止其他線程執(zhí)行該區(qū)域)及Release()(取消對其他線程的阻止)。
 
  (3)使用多重讀、獨占寫的同步器。

    當使用重要區(qū)段來保護全局內(nèi)存時,每次只有一個線程可以使用該內(nèi)存。這種保護可能會超出了需要,特別是有一個經(jīng)常讀但很少寫的對象或變量時更是如此。多個線程同時讀相同內(nèi)存但沒有線程寫內(nèi)存是沒有危險的。當有一些經(jīng)常被讀,但是很少寫的全局變量時,可用TMultiReadExclusiveWriteSynchronizer對象保護它。這個對象和重要區(qū)段一樣,但它允許多個線程同時讀,只要沒有線程寫即可。每個需要讀內(nèi)存的線程首先要調(diào)用Begin Read()函數(shù)(確保當前無其他線程寫內(nèi)存),線程完成對保護內(nèi)存讀操作后,要調(diào)用End Read()函數(shù)。任何線程需要寫保護內(nèi)存必須調(diào)用Begin Write()函數(shù)(確保當前無其他線程讀或?qū)憙?nèi)存),完成對保護內(nèi)存寫操作后,調(diào)用End Write()函數(shù)。
 
  (4)使用Synchronize函數(shù):Void __fast call Synchronize (TThreadMethod &Method);
 
  其中參數(shù)Method為一個不帶參數(shù)的過程名。在這個不帶參數(shù)的過程中是一些訪問VCL的代碼。我們可以在Execute過程中調(diào)用Synchronize過程來避免對VCL的并發(fā)訪問。程序運行期間的具體過程實際上是由Synchronize過程來通知主線程,然后主線程在適當?shù)臅r機來執(zhí)行Synchronize過程的參數(shù)列表中的那個不帶參數(shù)的過程。在多個線程的情況下,主線程將Synchronize過程發(fā)過來的通知放到消息隊列中,然后逐個地響應(yīng)這些消息。通過這種機制Synchronize實現(xiàn)了線程之間地同步。
2) 等待其他線程
 
  若線程必須等待另一線程完成某項任務(wù),可讓線程臨時中斷執(zhí)行。然后,要么等待另一線程完全執(zhí)行結(jié)束,要么等待另一線程通知完成了該任務(wù)。
 
  (1)等待線程執(zhí)行結(jié)束
 
  要等待另一線程執(zhí)行結(jié)束,使用它地Wait For()函數(shù)。Wait For函數(shù)直到那個線程終止才返回,終止的方式要么完成了其Execute()函數(shù),要么由于一個異常。
 
  (2)等待任務(wù)完成。

    有時,只需要等待線程完成一些操作而不是等待線程執(zhí)行結(jié)束。為此,可使用一個事件對象。事件對象(TEvent)應(yīng)具有全局范圍以便他們能夠為所有線程可見。當一個線程完成一個被其他線程依賴的操作時,調(diào)用TEvent::Set Event()函數(shù)。Set Event發(fā)出一個信號,以便其他線程可以檢查并得知操作完成。要關(guān)掉信號,則使用Reset Event()函數(shù)。
 
  例如,當必須等待若干線程完成其執(zhí)行而不是單個線程時。因為不知道哪個線程最后完成,也就不能對某個線程使用Wait For()函數(shù)。此時,可通過調(diào)用Set Event以在線程結(jié)束時累加計數(shù)值并在最后一個線程結(jié)束時發(fā)出信號以指示所有線程結(jié)束。
 
  多線程應(yīng)用程序編程實例
 
  下面是一個實現(xiàn)"生產(chǎn)者-消費者問題"的多線程應(yīng)用實例。在此例中,我們按上面介紹的方法構(gòu)造了兩個TThread的子類TProducerThread(生產(chǎn)者線程)和TCustomerThread(消費者線程),生產(chǎn)和消費的商品僅僅是一個整數(shù)。在協(xié)調(diào)生產(chǎn)和消費的過程中,重要區(qū)段(TCriticalSection)和事件(TEvent)得到了應(yīng)用。生產(chǎn)者通過TEvent類的對象Begin Consume來通知消費者開始消費,而消費者通過TEent類的對象Begin Produce通知生產(chǎn)者開始生產(chǎn)。程序中共有兩個生產(chǎn)者,一個消費者。在兩個生產(chǎn)者之間,通過TCriticalSection類的對象同步。其運行界面如圖1所示。
 


圖1 程序運行效果

  主要源程序如下所示:
 
  生產(chǎn)者線程:
 

 Void __fast call TProducerThread:: Execute ()
{
 //---- Place thread code here ----
 Int i = 0;
 Int j;
 while(i<100) //每個生產(chǎn)者線程生產(chǎn)100個商品
 {
  Sleep(1000);//延遲,為清楚得顯示執(zhí)行效果
  if(Form1->buffer_size > 0)//緩沖池不空,通知消費者消費
  {
   Form1->Begin Consumer->Set Event ();
 }
 Form1->Produce Guard->Acquire ();
 i++;
 StrResult = IntToStr (i);
 J = Form1->buffer_size;
 Form1->Product [j] = i;
 Form1->buffer_size++;
 Synchronize(Show Result);//刷新界面,顯示最新生產(chǎn)-消費狀況
 Form1->Begin Consumer->Set Event();//通知消費者消費
 if(Form1->buffer_size == 5)//緩沖池滿,掛起生產(chǎn)者線程,直到通知再生產(chǎn)
 {
  Form1->Begin Produce->Wait For (INFINITE);
 }
 Sleep (1000);
 Form1->Produce Guard->Release ();
}
While (Form1->buffer_size > 0)
{
 Form1->Begin Consumer->Set Event ();
}
}

  消費者線程:
 

 

 

 Void __fast call TConsumerThread::Execute()
{
 //---- Place thread code here ----
 Int j;
 For (int i = 0;i < 200;i++)
 {
  Sleep(100); //延遲,為清楚得顯示執(zhí)行效果
  Form1->Begin Consumer->Wait For(INFINITE);//掛起消費者線程,直到通知再消費
  J = Form1->buffer_size - 1;
  StrResult = IntToStr (Form1->Product [j]);
  Form1->buffer_size--;
  Synchronize(Show Result); //刷新界面,顯示最新生產(chǎn)-消費狀況
  if(Form1->buffer_size == 4)//緩沖池不再full,喚醒由于緩沖池full而掛起的生產(chǎn)者線程
  {
   Form1->Begin Produce->Set Event ();
  }
  Sleep (100);
 }
}

  結(jié)論
 
  本文討論了多線程編程及其可行性,說明了在Windows環(huán)境下進行多線程編程的意義,并重點討論了C++Builder平臺下如何開發(fā)多線程應(yīng)用程序這一問題,通過實現(xiàn)"生產(chǎn)者-消費者問題"這一著名的進程同步問題,比較清晰地反映了在Windows環(huán)境下進行多線程編程技術(shù)及其實現(xiàn)的作用和效果。
本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
delphi多線程編程
Delphi+多線程
QWorker專題-基于作業(yè)的Delphi/C++ Builder并行編程框架
用Delphi實現(xiàn)多線程數(shù)據(jù)采集
用多線程進行數(shù)據(jù)采集
LabVIEW編程之生產(chǎn)者消費者架構(gòu)
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服