国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

COM---多線程

2019-11-08 02:08:41
字體:
來源:轉載
供稿:網友

調整 將函數調用的參數從一個進程的地址空間傳到另一個進程的地址空間。

COM直接使用了Win32線程,但仍有細微差異。

Win32線程:用戶界面線程、工作線程 COM線程:套間線程(類似于用戶界面線程)、自由線程(類似于工作線程)

自由線程

若某個組件是有自由線程創建的,則任意線程均可在任意時候調用它,COM不能使之同步,同步工作將由COM移至組件本身。COM不能同步對組件的調用,所以自由線程不需要消息循環。

調整與同步

使用套間線程的情況下,所有的調整與同步均由COM完成。自由線程情況下,調整可能不需要,同步需要組件完成。

進程間的調用將被調整 同一線程中的調用將不被調整 對于套間線程中組件的調用將被調整 對于自由線程中組件的調用并不是總被調整 對于套間線程的調用將被同步 對于自由線程的調用將被同步 同一線程中的調用將由此線程本身完成同步

套間線程的實現

何時需要對接口手動調整? 跨越套間邊界但并沒有通過COM進行通信時。

例子: 在后臺增大對某個組件的一個計數器,并偶爾需要對顯示進行刷新。 主線程將創建此套間線程。套間線程中創建一個組件并周期性地修改此組件中的計數器。套間線程將給主線程傳遞一個接口指針,以便主線程可以獲得組件當前的計數值并顯示出來。需要: 1> 初始化COM庫 2> 具有一個消息循環 3> 對傳給主線程的接口進行調整

CSimpleApartment 為是套間概念更為具體,創建了CSimpleApartment這個類。 CSimpleApartment將在另外一個線程中創建組件的過程封裝起來。它將跨越兩個不同的線程,一部分由原線程調用,一部分由新的線程調用。

套間線程例子說明: 這里寫圖片描述

CSimpleApartment中的函數:

StartThread調用CreateThread創建一個新的線程。

CreateComponent接收一個被創建組件的CLSID并在StartThread啟動的線程上創建它。CreateComponent由原線程調用,使用一個事件(m_hCreateComponentEvent)以指示新套間線程調用CreateComponentOnThread創建新的組件。 它將完成4主要操作:1、將傳給它的參數復制到成員變量中;2、創建相應的組件;3、等待組件創建完成;4、對所請求的指向組件的接口指針進行反調整。

CreateComponentOnThread是一個純虛函數,由CSimpleApartment的派生類定義。創建玩新的組件后,設置m_hComponentReadyEvent表示組件已創建完成。 它將完成2個主要操作:1、調用CreateComponentOnThread純虛版本,并將傳給CreateComponent的參數傳給它;2、對接口進行調整。

ClassThreadPRoc是在套間線程中運行的函數,通過兩次使用m_hComponentReadyEvent指示線程的啟動與結束。使用MsgWaitForMultipleObjects等待三件事的發生:m_hCreateComponentEvent、一個Windows消息、一個超時事件,并作出相應處理。

WaitWithMessageLoop等待某個事件的發生,并處理Windows消息。

代碼:

//// Apart.cpp// - A simple C++ class, CSimpleApartment, encapsulates// creating a component on an apartment thread.//#include <windows.h>#include <stdlib.h>#include <objbase.h>#include <assert.h>#define __OUTPROC_SERVER_ // To get the proper definition of trace#include "Util.h"#undef __OUTPROC_SERVER_ #include "Apart.h"static inline void trace(char* msg) { Util::Trace("Apartment", msg, S_OK) ;} static inline void trace(char* msg, HRESULT hr) { Util::Trace("Apartment", msg, hr) ;}/////////////////////////////////////////////////////////////// Constructor//CSimpleApartment::CSimpleApartment() { m_ThreadId = 0 ; m_hThread = NULL ; m_hCreateComponentEvent = NULL ; m_hComponentReadyEvent = NULL ; m_pIStream = NULL ; m_hr = S_OK ; m_piid = NULL ; m_pclsid = NULL ; m_WaitTime = 500 ;} /////////////////////////////////////////////////////////////// Destructor//CSimpleApartment::~CSimpleApartment(){ // The thread must be stopped before we are deleted // because the WorkerFunction is in the derived class. assert(m_hThread == NULL) ;}/////////////////////////////////////////////////////////////// StartThread// - Create and start the thread.//BOOL CSimpleApartment::StartThread(DWord WaitTime) { if (IsThreadStarted()) { return FALSE ; } // 創建新線程 m_hThread = ::CreateThread(NULL, // Default security 0, // Default stack size RealThreadProc, (void*)this, CREATE_SUSPENDED, // Create the thread suspended. &m_ThreadId) ; // Get the Thread ID. if (m_hThread == NULL) { trace("StartThread failed to create thread.", GetLastError()) ; return FALSE ; } trace("StartThread successfully created thread.") ; // Create an event to signal the thread to create the component. m_hCreateComponentEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL) ; if (m_hCreateComponentEvent == NULL) { return FALSE ; } // Create an event for the thread to signal when it is finished. m_hComponentReadyEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL) ; if (m_hComponentReadyEvent == NULL) { return FALSE ; } trace("StartThread successfully created the events.") ; // Initialize the wait time. m_WaitTime = WaitTime ; // Thread was created suspended; start the thread. DWORD r = ResumeThread(m_hThread) ; assert(r != 0xffffffff) ; // Wait for the thread to start up before we continue. WaitWithMessageLoop(m_hComponentReadyEvent) ; return TRUE ;}/////////////////////////////////////////////////////////////// Stop Thread//void CSimpleApartment::StopThread(){ if (m_hThread != NULL) { // Stop the thread. PostThreadMessage(m_ThreadId, WM_QUIT, 0,0) ; // Wait for thread to stop. WaitWithMessageLoop(m_hComponentReadyEvent) ; m_hThread = NULL ; }}/////////////////////////////////////////////////////////////// Current thread status//BOOL CSimpleApartment::IsThreadStarted(){ return (m_hThread != NULL) ;}/////////////////////////////////////////////////////////////// Thread procedure//DWORD WINAPI CSimpleApartment::RealThreadProc(void* pv) { CSimpleApartment* pApartment = reinterpret_cast<CSimpleApartment*>(pv) ; return pApartment->ClassThreadProc() ;}/////////////////////////////////////////////////////////////// Thread procedure//DWORD CSimpleApartment::ClassThreadProc(){ // 初始化 COM 庫 HRESULT hr = CoInitialize(NULL) ; if (SUCCEEDED(hr)) { // 第1次使用m_hComponentReadyEvent // 指示新線程已經啟動 SetEvent(m_hComponentReadyEvent) ; // Wait for the signal to create a component. BOOL bContinue = TRUE ; while (bContinue ) { // 消息循環 // 比GetMessage/DispatchMessage效率高 switch(::MsgWaitForMultipleObjects( 1, &m_hCreateComponentEvent, FALSE, m_WaitTime, QS_ALLINPUT)) { // 創建組件 // 當事件m_hCreateComponentEvent被設置 // MsgWaitForMultipleObjects將停止等待 // 然后將調用CreateComponentOnThread case WAIT_OBJECT_0: CreateComponentOnThread() ; break ; // 處理Windows消息 case (WAIT_OBJECT_0 + 1): MSG msg ; // 取出消息 while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { if (msg.message == WM_QUIT) { bContinue = FALSE ; break ; } DispatchMessage(&msg) ; //將消息分發出去 } break ; // Do background processing. // 等待超時,調用CSimpleApartment::WorkerFunction // 此函數由CSimpleApartment派生類實現 case WAIT_TIMEOUT: WorkerFunction() ; break ; default: trace("Wait failed.", GetLastError()) ; } } // Uninitialize the COM Library. CoUninitialize() ; } // 第2次使用m_hComponentReadyEvent // 指示線程已經結束了 SetEvent(m_hComponentReadyEvent) ; return 0 ;}/////////////////////////////////////////////////////////////// CreateComponent helper function//HRESULT CSimpleApartment::CreateComponent(const CLSID& clsid, const IID& iid, IUnknown** ppI){ // 初始化共享數據 m_pIStream = NULL ; m_piid = &iid ; m_pclsid = &clsid ; // 指示何時需要套間線程調用CreateComponentEvent創建相應的組件 // 當設置m_hCreateComponentEvent,ClassThreadProc將調用 // CreateComponentOnThread SetEvent(m_hCreateComponentEvent) ; // Wait for the component to be created. trace("Wait for the component to be created.") ; if (WaitWithMessageLoop(m_hComponentReadyEvent)) { trace("The wait succeeded.") ; if (FAILED(m_hr)) // Did GetClassFactory fail? { return m_hr ; } if (m_pIStream == NULL) // Did the marshaling fail? { return E_FAIL ; } trace("Unmarshal the interface pointer.") ; // Unmarshal the interface. HRESULT hr = ::CoGetInterfaceAndReleaseStream(m_pIStream, iid, (void**)ppI) ; m_pIStream = NULL ; if (FAILED(hr)) { trace("CoGetInterfaceAndReleaseStream failed.", hr) ; return E_FAIL ; } return S_OK ; } trace("What happened here?") ; return E_FAIL ;}/////////////////////////////////////////////////////////////// CreateComponentOnThread helper function// - This function packages the parameters for the// CoCreateComponentOnThread function.// void CSimpleApartment::CreateComponentOnThread(){ IUnknown* pI = NULL ; // Call the derived class to actually create the component. // 調用CreateComponentOnThread的純虛版本 // 并將傳遞給CreateComponent的參數傳遞給它 m_hr = CreateComponentOnThread(*m_pclsid, *m_piid, &pI) ; if (SUCCEEDED(m_hr)) { trace("Successfully created component.") ; // Marshal the interface pointer to the server. // 對接口進行調整 HRESULT hr = ::CoMarshalInterThreadInterfaceInStream( *m_piid, //待調整的接口的IID pI, //待調整的接口 &m_pIStream) ; //推向待調整接口的流 assert(SUCCEEDED(hr)) ; // Release the pI Pointer. pI->Release() ; } else { trace("CreateComponentOnThread failed.", m_hr) ; } trace("Signal the main thread that the component is ready.") ; // 設置m_hComponentReadyEvent // 以告訴CreateComponent已完成了組件的創建 SetEvent(m_hComponentReadyEvent) ;}/////////////////////////////////////////////////////////////// BOOL WaitWithMessageLoop(HANDLE hEvent)// 等待某個事件的發生,處理Windows消息//BOOL CSimpleApartment::WaitWithMessageLoop(HANDLE hEvent){ while (TRUE) { // Wait for the event and for messages. DWORD dwReturn = ::MsgWaitForMultipleObjects(1, &hEvent, FALSE, INFINITE, QS_ALLINPUT) ; if (dwReturn == WAIT_OBJECT_0) { // Our event happened. return TRUE ; } else if (dwReturn == WAIT_OBJECT_0 + 1) { // Handle message to keep client alive. MSG msg ; while(::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { ::DispatchMessage(&msg) ; } } else { trace("WaitWithMessageLoop failed.", GetLastError()) ; return FALSE ; } }}

CClientApartment CClientApartment繼承CSimpleApartment,實現兩個虛擬函數:CreateComponentOnThread(調用CoCreateInstance創建新組件)、WorkerFunction。

// CreateTheComponent// 希望供在另一個線程中創建組件的客戶使用// 重載CreateComponentOnThread以調用CoCreateInstance//HRESULT CClientApartment::CreateComponentOnThread(const CLSID& clsid, const IID& iid, IUnknown** ppI) { HRESULT hr = ::CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, iid, (void**)ppI) ; if (SUCCEEDED(hr)) { // 查詢IX接口,以對WorkerFunction處理 hr = (*ppI)->QueryInterface(IID_IX, (void**)&m_pIX) ; if (FAILED(hr)) { // If we can't use it, don't let anybody use it. (*ppI)->Release() ; return E_FAIL ; } } return hr ;}/////////////////////////////////////////////////////////////// WorkerFunction - This function is called by the worker thread.//void CClientApartment::WorkerFunction(){ if (m_pIX) { m_pIX->Tick() ; }}

client.cpp

客戶收到WM_TIMER消息時,將調用OnTick,OnTick將調用IX::GetCurrentCount并將此數值顯示在窗口,此調用將被調整,以便能正確地跨越套間邊界。而WorkerFunction調用IX::Tick時,由于調用是在同一套間線程中,不需要被調整。

//// Client.cpp - Client implementation//#include <windows.h> #include <stdlib.h>#include <objbase.h>#include <assert.h>#define __OUTPROC_SERVER_ // To get the proper definition of trace#include "Util.h"#undef __OUTPROC_SERVER_ #include "Iface.h"#include "Apart.h"#include "Cli-Apt.h"static inline void trace(char* msg) { Util::Trace("Client", msg, S_OK) ;} static inline void trace(char* msg, HRESULT hr) { Util::Trace("Client", msg, hr) ;}/////////////////////////////////////////////////////////////// The client application//#include "resource.h"http://///////////////////////////////////////////////////////////// Global variables for main apartment//// Module handleHINSTANCE g_hModule = NULL ;// Handle to child listboxHWND g_hWndListBox = NULL ;// ID of the timerstatic UINT g_TimerId = 0 ;// Pointer to the interface on our componentstatic IX* g_pIX = NULL ; // Pointer to apartment thread classCClientApartment* g_pApartment = NULL ;/////////////////////////////////////////////////////////////// Functions prototypes//// Create and initialize the main window.HWND InitWindow(int nCmdShow) ;// Create the child listbox control.BOOL CreateChildListbox(HWND hWndParent, int cx, int cy) ;// The main window procedureextern "C" LONG APIENTRY MainWndProc(HWND hWnd, UINT message, UINT wParam, LONG lParam) ;// InitializeApartment - Create the thread and the component.void InitializeApartment(HWND hWndMain) ;// Timer tick message handlervoid OnTick() ;// Delete and tidy.void CleanUp(HWND hWnd) ;/////////////////////////////////////////////////////////////// WinMain function//extern "C" int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){ // Initialize the COM Library. HRESULT hr = CoInitialize(NULL) ; if (FAILED(hr)) { return 0 ; } // Create the main window. HWND hWndMain = InitWindow(nCmdShow) ; if (hWndMain) { // Initialize the apartment. InitializeApartment(hWndMain) ; // Wait for a message. MSG msg ; while (::GetMessage(&msg, 0, 0, 0) > 0) { ::DispatchMessage(&msg) ; } } // Uninitialize the COM Library. CoUninitialize() ; return 0 ;}/////////////////////////////////////////////////////////////// Initialize window.//HWND InitWindow(int nCmdShow) { // Fill in window class structure with parameters // that describe the main window. WNDCLASS wcListview ; wcListview.style = 0 ; wcListview.lpfnWndProc = (WNDPROC)MainWndProc ; wcListview.cbClsExtra = 0 ; wcListview.cbWndExtra = 0 ; wcListview.hInstance = g_hModule ; wcListview.hIcon = ::LoadIcon(g_hModule, MAKEINTRESOURCE(IDC_ICON)) ; wcListview.hCursor = ::LoadCursor(NULL, IDC_ARROW) ; wcListview.hbrBackground = ::GetStockObject(WHITE_BRUSH) ; wcListview.lpszMenuName = NULL ; wcListview.lpszClassName = "MyServerWinClass" ; BOOL bResult = ::RegisterClass(&wcListview) ; if (!bResult) { return NULL ; } HWND hWndMain ; hWndMain = ::CreateWindow("MyServerWinClass", "Component Server", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, g_hModule, NULL) ; // If window could not be created, return "failure". if (!hWndMain) { return NULL ; } // Make the window visible; update its client area; // and return "success". ::ShowWindow(hWndMain, nCmdShow) ; ::UpdateWindow(hWndMain) ; return hWndMain ; }/////////////////////////////////////////////////////////////// Create the listbox child control in the main window.//BOOL CreateChildListbox(HWND hWndParent, int cx, int cy) { // Create a listbox for output. g_hWndListBox = ::CreateWindow("LISTBOX", NULL, WS_CHILD | WS_VISIBLE | LBS_USETABSTOPS | WS_VSCROLL | LBS_NOINTEGRALHEIGHT, 0, 0, cx, cy, hWndParent, NULL, g_hModule, NULL) ; if (g_hWndListBox == NULL) { // Listbox not created ::MessageBox (NULL, "Listbox not created!", NULL, MB_OK ) ; return FALSE ; } else { return TRUE ; }}/////////////////////////////////////////////////////////////// InitializeApartment - Create the thread and the component.//void InitializeApartment(HWND hWnd){ // Create a simple apartment object. g_pApartment = new CClientApartment ; // Start the thread. if (g_pApartment->StartThread()) { trace("Successfully started thread.") ; // Create the component. HRESULT hr = g_pApartment->CreateComponent(CLSID_Component, IID_IX, (IUnknown**)&g_pIX) ; if (SUCCEEDED(hr)) { trace("Successfully created component.") ; // Initialize the component. HRESULT hr = g_pIX->SetStartCount(1000) ; if (FAILED(hr)) { trace("SetStartCount failed.", hr) ; } // Start a timer. g_TimerId = SetTimer(hWnd, 369, 2*1000, NULL) ; assert(g_TimerId != 0) ; return ; } }}/////////////////////////////////////////////////////////////// OnTick - Called when the window gets a WM_TIMER message//void OnTick(){ if (g_pIX != NULL) { // Get the current count. long c = 0 ; //當客戶調用IX::GetCurrentCount時,此調用將被調整,以便能正確 //跨越套間邊界 HRESULT hr = g_pIX->GetCurrentCount(&c) ; assert(SUCCEEDED(hr)) ; // Display the count. strstream sout ; sout << "The current count is : " << c << "." << ends ; trace(sout.str()) ; }}/////////////////////////////////////////////////////////////// Main window procedure//extern "C" LONG APIENTRY MainWndProc( HWND hWnd, // window handle UINT message, // type of message UINT wParam, // additional information LONG lParam) // additional information{ DWORD dwStyle ; switch (message) { case WM_CREATE: { // Create listbox control CREATESTRUCT* pcs = reinterpret_cast<CREATESTRUCT*>(lParam) ; if (!CreateChildListbox(hWnd, pcs->cx, pcs->cy)) { return -1 ; } } break ; case WM_SIZE: ::MoveWindow(g_hWndListBox, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE) ; break ; case WM_TIMER: OnTick() ; //調用IX::GetCurrentCount并將計數值顯示在窗口上 break ; case WM_DESTROY: // message: window being destroyed ::PostQuitMessage(0) ; break ; case WM_CLOSE: CleanUp(hWnd) ; //Fall through default: return (DefWindowProc(hWnd, message, wParam, lParam)); } return 0 ;}/////////////////////////////////////////////////////////////// CleanUp//void CleanUp(HWND hWnd){ // The list box is going away. g_hWndListBox = NULL ; // Kill the timer. if (g_TimerId != 0) { BOOL b = KillTimer(hWnd, g_TimerId) ; assert(b = TRUE) ; g_TimerId = 0 ; } // Remove interface pointer. if (g_pIX != NULL) { g_pIX->Release() ; g_pIX = NULL ; } if (g_pApartment != NULL) { g_pApartment->StopThread() ; delete g_pApartment ; g_pApartment = NULL ; }}

自由線程的實現

當創建一個自由線程時,此時創建的不再是一個線程而是一個套間。

CSimpleFree CSimpleAparatment變為了CSimpleFree。這里,CSimpleFree只能被在一個套間線程中運行的客戶來創建自由線程。

與CSimpleAparatment僅有的差別:ClassThreadProc 調用CoInitializeEx(0, COINIT_MULTITHREADED),在調用之前需要做2件事:1、定義_WINNT32_WINNT為0x0400或定義_WIN32_DCOM,否則OBJBASE.H將不包含CoInitializeEx的定義;2、運行時檢查操作系統是否支持CoInitializeEx

//// Thread procedure//BOOL CSimpleFree::ClassThreadProc(){ BOOL bReturn = FALSE ; // 檢查CoInitializeEx是否存在 typedef HRESULT (__stdcall *FPCOMINITIALIZE)(void*, DWORD) ; FPCOMINITIALIZE pCoInitializeEx = reinterpret_cast<FPCOMINITIALIZE>( ::GetProcAddress(::GetModuleHandle("ole32"), "CoInitializeEx")) ; if (pCoInitializeEx == NULL) { trace("This program requires the free-thread support in DCOM.") ; SetEvent(m_hComponentReadyEvent) ; return FALSE ; } // 初始化 COM 庫 HRESULT hr = pCoInitializeEx(0, COINIT_MULTITHREADED) ; //@ if (SUCCEEDED(hr)) { // Signal that we are starting. SetEvent(m_hComponentReadyEvent) ; // Set up array of events. HANDLE hEventArray[2] = { m_hCreateComponentEvent, m_hStopThreadEvent } ; // Wait for the signal to create a component. BOOL bContinue = TRUE ; while (bContinue) { //@ // 創建的是自由線程,不需要消息循環 // 將MsgWaitForMMultipleObjects替換掉 // 但被主線程調用,仍需要對消息進行處理 // 以使用戶界面不致被鎖起 switch(::WaitForMultipleObjects(2, hEventArray, FALSE, m_WaitTime)) { // Create the component. case WAIT_OBJECT_0: CreateComponentOnThread() ; break ; // Stop the thread. case (WAIT_OBJECT_0 +1): bContinue = FALSE ; bReturn = TRUE ; break ; // Do background processing. case WAIT_TIMEOUT: WorkerFunction() ; break ; default: trace("Wait failed.", GetLastError()) ; } } // Uninitialize the COM Library. CoUninitialize() ; } // Signal that we have finished. SetEvent(m_hComponentReadyEvent) ; return bReturn ;}

CClientFree

CClientFree與前面的CClientAparament是等價的,CClientFree繼承CSimepleFree并實現CreateComponent與WorkerFunction兩個虛擬函數,并添加了兩個新函數: ShareUnmarshaledInterfacePointer—返回CClientFree在其WorkerFunction所用的IX接口指針。此接口未經調整,因此,僅能從一個自由線程中使用它。 UseUnmarshaledInterfacePointer—將設置CClientFree對象在其WorkerFunction中使用的指針。

client.cpp: 在調用了InitializeThread后,客戶講調用InitializeThread2。

//// InitializeThread - 創建一個自由線程和一個組件//BOOL InitializeThread(HWND hWnd){ // Create a simple thread object. g_pThread = new CClientFree ; // Start the thread. if (g_pThread->StartThread()) { trace("Successfully started thread.") ; // Create the component. HRESULT hr = g_pThread->CreateComponent(CLSID_Component, IID_IX, (IUnknown**)&g_pIX) ; if (SUCCEEDED(hr)) { trace("Successfully created component.") ; // Initialize the component. HRESULT hr = g_pIX->SetStartCount(5000) ; if (FAILED(hr)) { trace("SetStartCount failed.", hr) ; return FALSE ; } // Start a timer. g_TimerId = SetTimer(hWnd, 369, 500, NULL) ; assert(g_TimerId != 0) ; } else { trace("Failed to create the component.") ; return FALSE ; } } else { trace("Failed starting thread.") ; return FALSE ; } return TRUE ;}/////////////////////////////////////////////////////////////// InitializeThread2// - Create a second thread, but use the component// from the first thread.// 建立第2個線程,但沒有建立第2個組件,而是共享了第1個線程創建的組件// 將創建一個CClientFree2對象而不是CClientFree對象// CClientFree2與CClientFree的唯一差別在于WorkerFunction實現不同//BOOL InitializeThread2(){ if (g_pThread == NULL) { return FALSE ; } // 創建第2個線程 // This thread has a different WorkerFunction. g_pThread2 = new CClientFree2 ; // Start the thread. if (g_pThread2->StartThread()) { trace("Successfully started second thread.") ; // Get the same pointer used by the first thread. IX* pIX = NULL ; pIX = g_pThread->ShareUnmarshaledInterfacePointer() ; assert(pIX != NULL) ; // Use this pointer in the second thread. g_pThread2->UseUnmarshaledInterfacePointer(pIX) ; pIX->Release() ; return TRUE ; } else { trace("Failed to start second thread.") ; return FALSE ; }}

CLI-FREE.cpp

//// WorkerFunction - This function is called by the worker thread.//void CClientFree::WorkerFunction(){ CSimpleLock Lock(m_hInterfaceMutex) ; if (m_pIX) { m_pIX->Tick(1) ; m_pIX->Left() ; }}

CLI-FREE.H

class CClientFree2 : public CClientFree{public: virtual void WorkerFunction() ;};

對組件的修改

對組件增加了新的成員外,還應使之成為線程安全的,這是因為有兩個線程分別增大和減少組件的計數值。

//// Lock.h// - This class provides a simple locking mechanism.//class CSimpleLock{public: // Lock CSimpleLock(HANDLE hMutex) { m_hMutex = hMutex ; WaitForSingleObject(hMutex, INFINITE) ; } // Unlock ~CSimpleLock() { // 釋放指定的互斥量 ReleaseMutex(m_hMutex) ; }private: HANDLE m_hMutex ;};

使用此類時,需要為其構造函數提供一個互斥量的句柄。構造函數將一直等待,直到指定的互斥量成為有信號的。

使用自由線程時,線程間的同步由程序員完成。

使用示例(CMPNT.CPP):

//// Interface IX - Implementation//HRESULT __stdcall CA::Tick(int delta) { //m_hCountMutex包含對m_count的訪問 CSimpleLock Lock(m_hCountMutex) ; m_count += delta ; return S_OK ;}HRESULT __stdcall CA::Left(){ //m_hHandMutex保護對m_bRightHand的訪問 CSimpleLock Lock(m_hHandMutex) ; m_bRightHand = FALSE ; return S_OK ;}

自由線程參數調整的優化

該優化是可實現的:自由線程中的組件直接將其指針傳遞給同一進程中的套間線程。

CMPNT.CPP:

CoCreateFreeThreadedMarshaler實現的是一個具有IMarshal接口的組件,可決定接口的客戶是否在同一進程中。若在同一進程,對接口調整時,所有指針都被原封不動地傳過去。若客戶在另外進程中,接口將被標準的調整程序進行調整處理。這樣,程序員無需關心客戶在什么地方。

NondelegatingQueryInterface將IMarshal查詢轉發給所創建的調整程序。

//// Initialize the component by creating the contained component//HRESULT CA::Init(){ HRESULT hr = CUnknown::Init() ; if (FAILED(hr)) { return hr ; } // Create a mutex to protect the count. m_hCountMutex = CreateMutex(0, FALSE, 0) ; if (m_hCountMutex == NULL) { return E_FAIL ; } // Create a mutex to protect the hand. m_hHandMutex = CreateMutex(0, FALSE, 0) ; if (m_hHandMutex == NULL) { return E_FAIL ; } // Aggregate the free-threaded marshaler. hr = ::CoCreateFreeThreadedMarshaler( GetOuterUnknown(), &m_pIUnknownFreeThreadedMarshaler) ; if (FAILED(hr)) { return E_FAIL ; } return S_OK ;}//// NondelegatingQueryInterface Implementation//HRESULT __stdcall CA::NondelegatingQueryInterface(const IID& iid, void** ppv){ if (iid == IID_IX) { return FinishQI(static_cast<IX*>(this), ppv) ; } else if (iid == IID_IMarshal) { return m_pIUnknownFreeThreadedMarshaler->QueryInterface(iid, ppv) ; } else { return CUnknown::NondelegatingQueryInterface(iid, ppv) ; }}

線程模型的注冊表關鍵字

COM需要知道進程中組件支持的線程模型,以便在跨越線程邊界時對其接口進行合適的調整與同步。為登記進程總組件的線程模型,可以給組件的InprocServer32關鍵字加上一個名為ThreadingModel的值。 ThreadingModel有3個可能的值: Apartment:套間線程使用的組件 Free:自由線程中使用的組件 Both:以上兩者都可以

若組件不關心線程問題,可以不指定任何值,COM將假定此組件不支持多線程。

一個進程中服務器提供的所有組件都應具有相同的線程模型。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 宝鸡市| 泰州市| 辽源市| 临高县| 图木舒克市| 类乌齐县| 舟山市| 西充县| 秀山| 马尔康县| 金塔县| 沐川县| 永靖县| 拉孜县| 卢氏县| 中西区| 舒城县| 收藏| 墨玉县| 涡阳县| 江孜县| 晋中市| 锡林郭勒盟| 宣汉县| 江油市| 丽水市| 三都| 增城市| 湘西| 麟游县| 桑植县| 偏关县| 黄浦区| 武威市| 恭城| 弋阳县| 惠东县| 禹城市| 牡丹江市| 蒙城县| 昌黎县|