1. 程式人生 > >C++多執行緒例項(_beginThreadex建立多執行緒)

C++多執行緒例項(_beginThreadex建立多執行緒)

C++多執行緒(二)(_beginThreadex建立多執行緒)  

C/C++ Runtime 多執行緒函式


一 簡單例項(來自codeprojct:http://www.codeproject.com/useritems/MultithreadingTutorial.asp
主執行緒建立2個執行緒t1和t2,建立時2個執行緒就被掛起,後來呼叫ResumeThread恢復2個執行緒,是其開始執行,呼叫WaitForSingleObject等待2個執行緒執行完,然後推出主執行緒即結束程序。

/*  file Main.cpp
 *
 *  This program is an adaptation of the code Rex Jaeschke showed in
 *  Listing 1 of his Oct 2005 C/C++ User's Journal article entitled
 *  "C++/CLI Threading: Part I".  I changed it from C++/CLI (managed)
 *  code to standard C++.
 *
 *  One hassle is the fact that C++ must employ a free (C) function
 *  or a static class member function as the thread entry function.
 *
 *  This program must be compiled with a multi-threaded C run-time
 *  (/MT for LIBCMT.LIB in a release build or /MTd for LIBCMTD.LIB
 *  in a debug build).
 *
 *                                      John Kopplin  7/2006
 
*/



#include 
<stdio.h>
#include 
<string>// for STL string class
#include <windows.h>// for HANDLE
#include <process.h>// for _beginthread()

using
namespace std;


class ThreadX
{
private:
  
int loopStart;
  
int loopEnd;
  
int dispFrequency;

public:
  
string threadName;

  ThreadX( 
int startValue, int endValue, int frequency )
  
{
    loopStart 
= startValue;
    loopEnd 
= endValue;
    dispFrequency 
= frequency;
  }


  
// In C++ you must employ a free (C) function or a static
  
// class member function as the thread entry-point-function.
  
// Furthermore, _beginthreadex() demands that the thread
  
// entry function signature take a single (void*) and returned
  
// an unsigned.
static unsigned __stdcall ThreadStaticEntryPoint(void* pThis)
  
{
      ThreadX 
* pthX = (ThreadX*)pThis;   // the tricky cast
      pthX->ThreadEntryPoint();           // now call the true entry-point-function

      
// A thread terminates automatically if it completes execution,
      
// or it can terminate itself with a call to _endthread().

      
return1;          // the thread exit code
  }


  
void ThreadEntryPoint()
  
{
     
// This is the desired entry-point-function but to get
     
// here we have to use a 2 step procedure involving
     
// the ThreadStaticEntryPoint() function.

    
for (int i = loopStart; i <= loopEnd; ++i)
    
{
      
if (i % dispFrequency ==0)
      
{
          printf( 
"%s: i = %d\n", threadName.c_str(), i );
      }

    }

    printf( 
"%s thread terminating\n", threadName.c_str() );
  }

}
;


int main()
{
    
// All processes get a primary thread automatically. This primary
    
// thread can generate additional threads.  In this program the
    
// primary thread creates 2 additional threads and all 3 threads
    
// then run simultaneously without any synchronization.  No data
    
// is shared between the threads.

    
// We instantiate an object of the ThreadX class. Next we will
    
// create a thread and specify that the thread is to begin executing
    
// the function ThreadEntryPoint() on object o1. Once started,
    
// this thread will execute until that function terminates or
    
// until the overall process terminates.

    ThreadX 
* o1 =new ThreadX( 012000 );

    
// When developing a multithreaded WIN32-based application with
    
// Visual C++, you need to use the CRT thread functions to create
    
// any threads that call CRT functions. Hence to create and terminate
    
// threads, use _beginthreadex() and _endthreadex() instead of
    
// the Win32 APIs CreateThread() and EndThread().

    
// The multithread library LIBCMT.LIB includes the _beginthread()
    
// and _endthread() functions. The _beginthread() function performs
    
// initialization without which many C run-time functions will fail.
    
// You must use _beginthread() instead of CreateThread() in C programs
    
// built with LIBCMT.LIB if you intend to call C run-time functions.

    
// Unlike the thread handle returned by _beginthread(), the thread handle
    
// returned by _beginthreadex() can be used with the synchronization APIs.

    HANDLE   hth1;
    unsigned  uiThread1ID;

    hth1 
= (HANDLE)_beginthreadex( NULL,         // security
0,            // stack size
                                   ThreadX::ThreadStaticEntryPoint,
                                   o1,           
// arg list
                                   CREATE_SUSPENDED,  // so we can later call ResumeThread()
&uiThread1ID );

    
if ( hth1 ==0 )
        printf(
"Failed to create thread 1\n");

    DWORD   dwExitCode;

    GetExitCodeThread( hth1, 
&dwExitCode );  // should be STILL_ACTIVE = 0x00000103 = 259
    printf( "initial thread 1 exit code = %u\n", dwExitCode );

    
// The System::Threading::Thread object in C++/CLI has a "Name" property.
    
// To create the equivalent functionality in C++ I added a public data member
    
// named threadName.

    o1
->threadName ="t1";

    ThreadX 
* o2 =new ThreadX( -100000002000 );

    HANDLE   hth2;
    unsigned  uiThread2ID;

    hth2 
= (HANDLE)_beginthreadex( NULL,         // security
0,            // stack size
                                   ThreadX::ThreadStaticEntryPoint,
                                   o2,           
// arg list
                                   CREATE_SUSPENDED,  // so we can later call ResumeThread()
&uiThread2ID );

    
if ( hth2 ==0 )
        printf(
"Failed to create thread 2\n");

    GetExitCodeThread( hth2, 
&dwExitCode );  // should be STILL_ACTIVE = 0x00000103 = 259
    printf( "initial thread 2 exit code = %u\n", dwExitCode );

    o2
->threadName ="t2";

    
// If we hadn't specified CREATE_SUSPENDED in the call to _beginthreadex()
    
// we wouldn't now need to call ResumeThread().

    ResumeThread( hth1 );   
// serves the purpose of Jaeschke's t1->Start()

    ResumeThread( hth2 );//你需要恢復執行緒的控制代碼 使用該函式能夠啟用執行緒的執行

    
// In C++/CLI the process continues until the last thread exits.
    
// That is, the thread's have independent lifetimes. Hence
    
// Jaeschke's original code was designed to show that the primary
    
// thread could exit and not influence the other threads.

    
// However in C++ the process terminates when the primary thread exits
    
// and when the process terminates all its threads are then terminated.
    
// Hence if you comment out the following waits, the non-primary
    
// threads will never get a chance to run.

    WaitForSingleObject( hth1, INFINITE );
    WaitForSingleObject( hth2, INFINITE );
           //WaitForSingleObject函式用來檢測 hHandle 事件的訊號狀態,當函式的執行時間超過 dwMilliseconds 就返回,
     //但如果引數
dwMilliseconds INFINITE 時函式將直到相應時間事件變成有訊號狀態才返回,否則就一直等待下去
     //,直到
WaitForSingleObject有返回直才執行後面的程式碼

    GetExitCodeThread( hth1, 
&dwExitCode );
    printf( 
"thread 1 exited with code %u\n", dwExitCode );

    GetExitCodeThread( hth2, 
&dwExitCode );
    printf( 
"thread 2 exited with code %u\n", dwExitCode );
         //
//GetExitCodeThread這個函式是獲得執行緒的退出碼,  第二個引數是一個 DWORD的指標,
//使用者應該使用一個 DWORD 型別的變數去接收資料,返回的資料是執行緒的退出碼,
//第一個引數是執行緒控制代碼,用 CreateThread 建立執行緒時獲得到。
//通過執行緒退出碼可以判斷執行緒是否正在執行,還是已經退出。


    // The handle returned by _beginthreadex() has to be closed
    
// by the caller of _beginthreadex().

    CloseHandle( hth1 );
    CloseHandle( hth2 );

    delete o1;
    o1 
= NULL;

    delete o2;
    o2 
= NULL;

    printf(
"Primary thread terminating.\n");
}


二解釋
1)如果你正在編寫C/C++程式碼,決不應該呼叫CreateThread。相反,應該使用VisualC++執行期庫函式_beginthreadex,推出也應該使用_endthreadex。如果不使用Microsoft的VisualC++編譯器,你的編譯器供應商有它自己的CreateThred替代函式。不管這個替代函式是什麼,你都必須使用。

2)因為_beginthreadex和_endthreadex是CRT執行緒函式,所以必須注意編譯選項runtimelibaray的選擇,使用MT或MTD。

3) _beginthreadex函式的引數列表與CreateThread函式的引數列表是相同的,但是引數名和型別並不完全相同。這是因為Microsoft的C/C++執行期庫的開發小組認為,C/C++執行期函式不應該對Windows資料型別有任何依賴。_beginthreadex函式也像CreateThread那樣,返回新建立的執行緒的控制代碼。
下面是關於_beginthreadex的一些要點:
&8226;每個執行緒均獲得由C/C++執行期庫的堆疊分配的自己的tiddata記憶體結構。(tiddata結構位於Mtdll.h檔案中的VisualC++原始碼中)。

&8226;傳遞給_beginthreadex的執行緒函式的地址儲存在tiddata記憶體塊中。傳遞給該函式的引數也儲存在該資料塊中。

&8226;_beginthreadex確實從內部呼叫CreateThread,因為這是作業系統瞭解如何建立新執行緒的唯一方法。

&8226;當呼叫CreatetThread時,它被告知通過呼叫_threadstartex而不是pfnStartAddr來啟動執行新執行緒。還有,傳遞給執行緒函式的引數是tiddata結構而不是pvParam的地址。

&8226;如果一切順利,就會像CreateThread那樣返回執行緒控制代碼。如果任何操作失敗了,便返回NULL

4) _endthreadex的一些要點:
&8226;C執行期庫的_getptd函式內部呼叫作業系統的TlsGetValue函式,該函式負責檢索呼叫執行緒的tiddata記憶體塊的地址。

&8226;然後該資料塊被釋放,而作業系統的ExitThread函式被呼叫,以便真正撤消該執行緒。當然,退出程式碼要正確地設定和傳遞。

5)雖然也提供了簡化版的的_beginthread和_endthread,但是可控制性太差,所以一般不使用。

6)執行緒handle因為是核心物件,所以需要在最後closehandle

7)更多的API:

HANDLE GetCurrentProcess();

HANDLE GetCurrentThread();

DWORD GetCurrentProcessId();

DWORD GetCurrentThreadId()。

DWORD SetThreadIdealProcessor(HANDLE hThread,DWORD dwIdealProcessor);

BOOL SetThreadPriority(HANDLE hThread,int nPriority);

BOOL SetPriorityClass(GetCurrentProcess(),  IDLE_PRIORITY_CLASS);

BOOL GetThreadContext(HANDLE hThread,PCONTEXT pContext);BOOL SwitchToThread();

三注意
1)C++主執行緒的終止,同時也會終止所有主執行緒建立的子執行緒,不管子執行緒有沒有執行完畢。所以上面的程式碼中如果不呼叫WaitForSingleObject,則2個子執行緒t1和t2可能並沒有執行完畢或根本沒有執行。
2)如果某執行緒掛起,然後有呼叫WaitForSingleObject等待該執行緒,就會導致死鎖。所以上面的程式碼如果不呼叫resumethread,則會死鎖。

來源自自1999年7月MSJ雜誌的《Win32 Q&A》欄目

你也許會說我一直用CreateThread來建立執行緒,一直都工作得好好的,為什麼要用_beginthreadex來代替CreateThread,下面讓我來告訴你為什麼。
回答一個問題可以有兩種方式,一種是簡單的,一種是複雜的。
如果你不願意看下面的長篇大論,那我可以告訴你簡單的答案:_beginthreadex在內部呼叫了CreateThread,在呼叫之前_beginthreadex做了很多的工作,從而使得它比CreateThread更安全。

相關推薦

C++執行例項(_beginThreadex建立執行)

C++多執行緒(二)(_beginThreadex建立多執行緒)   C/C++ Runtime 多執行緒函式 一 簡單例項(來自codeprojct:http://www.codeproject.com/useritems/MultithreadingTutorial.asp) 主執行緒建立2個執行緒t1

python執行———2、建立執行的兩種方式

 法一、使用Thread類例項化 法二、繼承Thread來實現多執行緒 #對於io操作來說,多執行緒和多程序效能差別不大 #1、使用Thread類例項化 import time import threading def get_detail_html(url): prin

Qt執行學習:建立執行

【為什麼要用多執行緒?】 傳統的圖形使用者介面應用程式都只有一個執行執行緒,並且一次只執行一個操作。如果使用者從使用者介面中呼叫一個比較耗時的操作,當該操作正在執行時,使用者介面通常會凍結而不再響應。這個問題可以用事件處理和多執行緒來解決。 【Linux有執行緒的概念嗎?

一個php腳本執行中實例次PDO,會建立次數據庫連接。

重用 slist OS play 類實例化 每次 連接 inf log 腳本代碼: <?php try { $dbh = new PDO(‘mysql:host=localhost;dbname=test‘, ‘root‘, ‘root‘); } ca

C++11的執行類,建立執行,如何設定優先順序?

SetThreadPriorityThe SetThreadPriority function sets the priority value for the specified thread. This value, together with the priority 

tensorflow例項(7)--建立層神經網路

本文將建立多層神經網路的函式,這個函式是一個簡單的通用函式,通過最後的測試,可以建立一些多次方程的模型,並通過matplotlib.pyplot演示模型建立過程中的資料變化情況以下三張圖片是生成的效果,每張圖的藍點都表示為樣本值,紅點表示最終預測效果,本例帶有點動畫效果,可以

一個MySql例項自動建立個Activiti資料庫問題

一次使用SSH和Activiti6開發的專案中,在伺服器啟動的時候就報錯:org.apache.ibatis.exceptions.PersistenceException: ### Error querying database.  Cause: java.sql.SQLS

IDEA+Maven+個Module模組(建立模組SpringBoot整合專案)

最近在學習springboot,先從建立專案開始,一般專案都是一個專案下會有多個模組,這裡先建立一個最簡單的例項,一個專案下有一個springboot模組專案提供web服務,引用另一個java專案(相當於業務邏輯)  期望的專案結構如下  springboot-test  —

JBPM4入門——6.流程例項建立執行

package com.test.test; import java.util.Iterator; import java.util.List; import org.jbpm.api.ProcessDefinition; import org.jbpm.api.ProcessDefinitionQuer

C++執行例項執行建立—排程—正確結束)

C++中的多執行緒程式設計時一個非常複雜的東西,使用過程中一定要注意執行緒的排程和結束。那麼為什麼要用多執行緒呢?舉一個例子,介面裡有個按鈕,按鈕按下後,這個操作需要非常長的時間才能完成,那麼在操作未完成之前,會將介面卡死,無法進行其他操作,這就是需要多執行緒的原因,一個主

c++執行例項

主要總結了基於C++的多執行緒函式CreateThread,互斥鎖(或者稱資源獨佔)函式CreateMutex,等待資源函式WaitForSingleObject,關閉執行緒函式(其實是關閉執行緒的控制代碼)CloseHanlde,釋放互斥鎖函式ReleaseMutex的

ndk執行需要獲取JNIEnv 或c通過類名+包名建立物件使用如下方法

JavaVM* mJavaVM; static pthread_key_t mThreadKey; static void Android_JNI_ThreadDestroyed(void* value) { JNIEnv *env = (JNIEnv*)

執行程式設計之建立執行(Windows下C++實現)

執行緒概述 理解Windows核心物件 執行緒是系統核心物件之一。在學習執行緒之前,應先了解一下核心物件。核心物件是系統核心分配的一個記憶體塊,該記憶體塊描述的是一個數據結構,其成員負責維護物件的各種資訊。核心物件的資料只能由系統核心來訪問,應用程式無法在記

C++之執行(POSIX執行例項

1.程序同時建立5個執行緒,各自呼叫同一個函式 #include <iostream> #include <pthread.h> //多執行緒相關操作標頭檔案,可移植眾多平臺 using namespace std; #define NUM_TH

執行第一篇:使用_beginthreadex建立執行

我們先來了解一下執行緒的相關函式:CreateThread函式:HANDLE WINAPI CreateThread ( _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes , // pointer to security attributes _I

C語言執行例項之pthread的應用(在windows下的應用(win7))

Pthread是由POSIX提出的一套通用的執行緒庫,在linux平臺下,它被廣泛的支援,而windows平臺下,卻並不被支援,而pthreads-w32為我們提供瞭解決方案,本文我們準備在我們的windows平臺下進行pthread-w32的安裝,在網路上有類

在linux c++類中的成員函式裡建立執行要注意的地方

如何在linux 下c++中類的成員函式中建立多執行緒 linux系統中執行緒程式庫是POSIX pthread。POSIX pthread它是一個c的庫,用C語言進行多執行緒程式設計我這裡就不多說了,網上的例子很多。但是如何在C++的類中實現多執行緒程式設計呢?如果套

Objecttive-C 建立執行

在Objecttive-C裡建立多執行緒一般有兩種方法, 一種是initWithTarget,還有一種是detachNewThreadSelector。 下面是兩個例項,建立多執行緒的例項,支援傳遞引數. initWithTarget方式 // // main.m /

C++執行例項之臨界區同步

本篇是對上一篇 進行了重構,增加了windos下的臨界區鎖。 臨界區的特點:非核心物件,只能在window下使用,linux下不能使用;只能在同一程序內的執行緒間使用,速度快。 互斥量特點:互斥量是核心物件,可以用於程序內也可以在程序間互斥,速度相對互斥量慢點,也可以

Objective-C高階程式設計:iOS與OS X執行和記憶體管理

這篇文章主要給大家講解一下GCD的平時不太常用的API,以及文末會貼出GCD定時器的一個小例子。 需要學習的朋友可以通過網盤免費下載pdf版 (先點選普通下載-----再選擇普通使用者就能免費下載了)http://putpan.com/fs/cy1i1beebn7s0h4u9/ 1.G