当前位置: 代码迷 >> 综合 >> 线程同步Thread Synchronous(C++)
  详细解决方案

线程同步Thread Synchronous(C++)

热度:30   发布时间:2023-10-31 06:08:10.0

同步(synchronous):当程序1调用程序2时,程序1 停下不动,直到程序2完成回到程序1来,程序1才继续下去;

异步(asynchronous):如果程序1调用程序2后,径自继续自己的下一个动作,那么两者之间就是asynchronous;

一.Win32

(1)事件(Event)

#include<windows.h>
使用CreateEvent创建一个事件
HANDLE WINAPI CreateEvent(  
_In_opt_ LPSECURITY_ATTRIBUTES lpEventAttributes,                    //安全属性
_In_     BOOL                  bManualReset,                         			//设置信号复位方式为自动恢复为无信号状态(FALSE)还是手动恢复为无信号状态(TRUE)_In_     BOOL                  bInitialState,                       				 //初始状态  _In_opt_ LPCTSTR               lpName                               			 //信号名称,可以为Null
);

使用SetEvent设置某个时间有信号

使用WaitForSingleObject等待某个事件的信号

使用方法:

第一种情况 自动恢复到无信号状态

hEvent = CreateEvent(NULL, FALSE, TRUE, NULL); //复位方式为自动恢复到无信号状态,且初始状态为有信号.

DWORD dReturn = WaitForSingleObject(hEvent, 等待时间);  // 即调用完该方法后,hEvent 就变为无信号状态, 需要调用setEvent使其为有信号状态

SetEvent(hEvent)

第二种情况手动恢复到无信号状态

hEvent = CreateEvent(NULL, TRUE, TRUE, NULL); //复位方式为手动恢复到无信号状态,且初始状态为有信号.

DWORD dReturn = WaitForSingleObject(hEvent, 等待时间); //调用该方法后,hEvent 就会自动再次变为有信号状态,如果需要将hEvent设置为无信号状态,则需要手动使用下面的语句:

ResetEvent(hEvent);

#include "stdafx.h"
#include <windows.h>//安全描述符, 手工重置开关,初始状态 TURE/FALSE
//TURE 信号 
HANDLE g_event = CreateEvent(NULL,TRUE,FALSE,NULL); //只要有状态就会去通知DWORD WINAPI ThreadProc1(LPVOID lpParameter){//当事件变成通知TCHAR szBuffer[10] = {0};WaitForSingleObject(g_event,INFINITE); //等待单独对象  无限等待Sleep(2000);printf("线程1执行了!\n");getchar();return 0;
}
DWORD WINAPI ThreadProc2(LPVOID lpParameter){//当事件变成通知TCHAR szBuffer[10] = {0};WaitForSingleObject(g_event,INFINITE);Sleep(2000);printf("线程2执行了!\n");getchar();return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{//创建通知类型HANDLE ArrThread[2];//创建俩个线程ArrThread[0] = CreateThread(
NULL,
0,
ThreadProc1,
NULL,
0,
0);ArrThread[1] = CreateThread(
NULL,
0,
ThreadProc2,
NULL,
0,
0);//设置通知类型的信号printf("回车设置事件信号\n");getchar();SetEvent(g_event);//等待线程全部结束WaitForMultipleObjects(2,ArrThread,TRUE,INFINITE);CloseHandle(ArrThread[0]);CloseHandle(ArrThread[1]);CloseHandle(g_event);return 0;
}

(2)信号量(semaphore)

/*头文件*/ 

#include <windows.h>

一般使用CreateSemaphore()创建信号量

使用WaitForSingleObject()设置某个等待信号量为有信号状态

使用ReleaseSemaphore()释放信号量

信号量的特点和用途可用下列几句话定义:

1)如果当前资源的数量大于0,则信号量有效;

2)如果当前资源数量是0,则信号量无效;

3)系统决不允许当前资源的数量为负值;

4)当前资源数量决不能大于最大资源数量

#include <windows.h>
#include <stdio.h>#define MAX_SEM_COUNT 10
#define THREADCOUNT 12HANDLE ghSemaphore;DWORD WINAPI ThreadProc( LPVOID );int main( void )
{HANDLE aThread[THREADCOUNT];DWORD ThreadID;int i;// Create a semaphore with initial and max counts of MAX_SEM_COUNTghSemaphore = CreateSemaphore( NULL,           // default security attributesMAX_SEM_COUNT,  // initial countMAX_SEM_COUNT,  // maximum countNULL);          // unnamed semaphoreif (ghSemaphore == NULL) {printf("CreateSemaphore error: %d\n", GetLastError());return 1;}// Create worker threadsfor( i=0; i < THREADCOUNT; i++ ){aThread[i] = CreateThread( NULL,       // default security attributes0,          // default stack size(LPTHREAD_START_ROUTINE) ThreadProc, NULL,       // no thread function arguments0,          // default creation flags&ThreadID); // receive thread identifierif( aThread[i] == NULL ){printf("CreateThread error: %d\n", GetLastError());return 1;}}// Wait for all threads to terminateWaitForMultipleObjects(THREADCOUNT, aThread, TRUE, INFINITE);// Close thread and semaphore handlesfor( i=0; i < THREADCOUNT; i++ )CloseHandle(aThread[i]);CloseHandle(ghSemaphore);return 0;
}DWORD WINAPI ThreadProc( LPVOID lpParam )
{// lpParam not used in this exampleUNREFERENCED_PARAMETER(lpParam);DWORD dwWaitResult; BOOL bContinue=TRUE;while(bContinue){// Try to enter the semaphore gate.dwWaitResult = WaitForSingleObject( ghSemaphore,   // handle to semaphore0L);           // zero-second time-out intervalswitch (dwWaitResult) { // The semaphore object was signaled.case WAIT_OBJECT_0: // TODO: Perform taskprintf("Thread %d: wait succeeded\n", GetCurrentThreadId());bContinue=FALSE;            // Simulate thread spending time on taskSleep(5);// Release the semaphore when task is finishedif (!ReleaseSemaphore( ghSemaphore,  // handle to semaphore1,            // increase count by oneNULL) )       // not interested in previous count{printf("ReleaseSemaphore error: %d\n", GetLastError());}break; // The semaphore was nonsignaled, so a time-out occurred.case WAIT_TIMEOUT: printf("Thread %d: wait timed out\n", GetCurrentThreadId());break; }}return TRUE;
}

(3)互斥量(mutex)

/*头文件*/

#include <windows.h>

一般使用CreateMutex创建互斥量

使用WaitForSingleObject()设置某个互斥量为有信号状态

使用ReleaseMutex()释放互斥量

#include <windows.h>
#include <stdio.h>#define THREADCOUNT 2HANDLE ghMutex; DWORD WINAPI WriteToDatabase( LPVOID );int main( void )
{HANDLE aThread[THREADCOUNT];DWORD ThreadID;int i;// Create a mutex with no initial ownerghMutex = CreateMutex( NULL,              // default security attributesFALSE,             // initially not ownedNULL);             // unnamed mutexif (ghMutex == NULL) {printf("CreateMutex error: %d\n", GetLastError());return 1;}// Create worker threadsfor( i=0; i < THREADCOUNT; i++ ){aThread[i] = CreateThread( NULL,       // default security attributes0,          // default stack size(LPTHREAD_START_ROUTINE) WriteToDatabase, NULL,       // no thread function arguments0,          // default creation flags&ThreadID); // receive thread identifierif( aThread[i] == NULL ){printf("CreateThread error: %d\n", GetLastError());return 1;}}// Wait for all threads to terminateWaitForMultipleObjects(THREADCOUNT, aThread, TRUE, INFINITE);// Close thread and mutex handlesfor( i=0; i < THREADCOUNT; i++ )CloseHandle(aThread[i]);CloseHandle(ghMutex);return 0;
}DWORD WINAPI WriteToDatabase( LPVOID lpParam )
{ // lpParam not used in this exampleUNREFERENCED_PARAMETER(lpParam);DWORD dwCount=0, dwWaitResult; // Request ownership of mutex.while( dwCount < 20 ){ dwWaitResult = WaitForSingleObject( ghMutex,    // handle to mutexINFINITE);  // no time-out intervalswitch (dwWaitResult) {// The thread got ownership of the mutexcase WAIT_OBJECT_0: __try { // TODO: Write to the databaseprintf("Thread %d writing to database...\n", GetCurrentThreadId());dwCount++;} __finally { // Release ownership of the mutex objectif (! ReleaseMutex(ghMutex)) { // Handle error.} } break; // The thread got ownership of an abandoned mutex// The database is in an indeterminate statecase WAIT_ABANDONED: return FALSE; }}return TRUE; 
}

4)临界区(Critical section)

/*头文件*/

#include<windows.h>

一般使用InitializeCriticalSection()初始化临界区

使用CRITICAL_SECTION定义临界区句柄

使用EnterCriticalSection()进入临界区

使用LeaveCriticalSection()释放/离开临界区

使用DeleteCriticalSection销毁临界区

#include "stdafx.h" 
#include <Windows.h> DWORD g_cnt1; 
DWORD g_cnt2; 
BOOL g_bContinue = TRUE; 
CRITICAL_SECTION cs; DWORD WINAPI ThreadProc(__in LPVOID lpParameter) 
{   ::EnterCriticalSection(&cs);   while(g_bContinue)   {     g_cnt1++;     g_cnt2++;   }   ::LeaveCriticalSection(&cs);   return 0; 
}   
int _tmain(int argc, _TCHAR* argv[]) 
{   HANDLE hThread[2];   g_cnt1 = g_cnt2 = 0;   ::InitializeCriticalSection(&cs);     hThread[0] = ::CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);   hThread[1] = ::CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);     Sleep(1000);   g_bContinue = FALSE;   ::WaitForMultipleObjects(2, hThread, TRUE, INFINITE);   printf("g_cnt1=%d\n",g_cnt1);   printf("g_cnt2=%d\n",g_cnt2);     ::DeleteCriticalSection(&cs);     ::CloseHandle(hThread[0]);   ::CloseHandle(hThread[1]);   return 0; 
}

二.MFC

MFC提供了多种同步对象,如CEvent,CCriticalSection,CSemaphore,CMutex.另外MFC提供了线程的辅助类CSingleLock和CMutiLock

CSingleLock:表示多线程程序中用于控制对一个资源的访问的访问控制机制。

CSingleLock singleLock(&m_Mutex);
// Attempt to lock the shared resource
singleLock.Lock(100);    
// Wait 100 ms...
// Has the resource been successfully locked?
if (singleLock.IsLocked())
{// We were able to lock the resource; we may now work with the data associated with the mutex...// Now that we are finished, unlock the resource for others.singleLock.Unlock();
}

CMultiLock :表示多线程程序中用于控制对多个资源的访问的访问控制机制,

与CSingleLock不同点在于:

CMultiLock::CMultiLock(

CSyncObject* pObject[],这个地方是一个异步信号数组

DWORD dwCount,

BOOL bInitialLock)

(1)事件(Event)

如下程序计算1 到 1000000的素数的个数并打印出个数。CEvent event; //定义个事件对象
void CThreadEventDlg::OnPrime()
{// TODO:  在此添加命令处理程序代码int n = 0;AfxBeginThread(Calculateprime, (LPVOID)&n, THREAD_PRIORITY_BELOW_NORMAL, 0);event.Lock(); //检测事件的发生,当计算线程计算完成后,SetEvent()将信号设为有信号后,才可打印CString str;str.Format(_T("The Prime Numbers from 1 to 1000000 is %d"), n);AfxMessageBox(str);//输出素数的个数event.Unlock(); //将事件对象恢复为无信号状态}
UINT Calculateprime(LPVOID pParam)
{int* n = (int*)pParam;long m, k, i;for (m = 1; m <= 1000000; m = m + 2){k = (long)sqrt((double)m);for (i = 2; i <= k; i++){if (0 == m %i){break;}}if (i >= k + 1){*n = *n + 1;}}event.SetEvent(); //将事件对象激活return 0;
}

(2)信号量(semaphore)

CSemaphore sem(int init , int max)   //init为初始信号量, max为最大信号量. 执行Lock会减少信号量, 相对地执行Unlock将增大信号量.
CSingleLock singlelock(&sem);
singlelock.Lock();
singlelock.Unlock();

(3)互斥量(mutex)

CMutex mute;
CSingleLock singlelock(&mute);
singlelock.Lock();
singlelock.Unlock();

(4)临界区(Critical section)

CCriticalSection cs;
CSingleLock singlelock(&cs);
singlelock.Lock();
singlelock.Unlock();

  相关解决方案