同步(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();