线程间的同步机制(2)
来源:互联网 发布:手机淘宝代销流程 编辑:程序博客网 时间:2024/06/05 17:35
----------------------------------------------------------------------------------------
//示例代码:
///////////////////////////////////////////////////////////////////////////////
①、Mutex(互斥器)
使用方法:
1、创建一个互斥器:CreateMutex;
2、打开一个已经存在的互斥器:OpenMutex;
3、获得互斥器的拥有权:WaitForSingleObject、WaitForMultipleObjects 等一类等待的函数……(可能造成阻塞);
4、释放互斥器的拥有权:ReleaseMutex;
5、关闭互斥器:CloseHandle;
※ 命名标准:Mutex 可以跨进程使用,所以其名称对整个系统而言是全局的,所以命名不要过于普通,类似:Mutex、Object 等。
最好想一些独一无二的名字等!
固有特点(优点+缺点):
1、是一个系统核心对象,所以有安全描述指针,用完了要 CloseHandle 关闭句柄,这些是内核对象的共同特征;
2、因为是核心对象,所以执行速度会比 Critical Sections 慢几乎100倍的时间(当然只是相比较而言);
3、因为是核心对象,而且可以命名,所以可以跨进程使用;
4、Mutex 使用正确的情况下不会发生死锁;
5、在“等待”一个 Mutex 的时候,可以指定“结束等待”的时间长度;
6、可以检测到当前拥有互斥器所有权的线程是否已经退出!Wait……函数会返回:WAIT_ABANDONED
===================================================
②、Semaphores(信号量)
租车例子的比喻很恰当!
使用方法:
1、创建一个信号量:CreateSemaphore;
2、打开一个已经存在的信号量:OpenSemaphore;
3、获得信号量的一个占有权:WaitForSingleObject、WaitForMultipleObjects 等一类等待的函数……(可能造成阻塞);
4、释放信号量的占有权:ReleaseSemaphore;
5、关闭信号量:CloseHandle;
※ 命名标准:Semaphores 可以跨进程使用,所以其名称对整个系统而言是全局的,所以命名不要过于普通,类似:Semaphore、Object 等
。
最好想一些独一无二的名字等!
固有特点(优点+缺点):
1、是一个系统核心对象,所以有安全描述指针,用完了要 CloseHandle 关闭句柄,这些是内核对象的共同特征;
2、因为是核心对象,所以执行速度稍慢(当然只是相比较而言);
3、因为是核心对象,而且可以命名,所以可以跨进程使用;
4、Semaphore 使用正确的情况下不会发生死锁;
5、在“等待”一个 信号量 的时候,可以指定“结束等待”的时间长度;
6、非排他性的占有,跟 Critical Sections 和 Mutex 不同,这两种而言是排他性占有,
即:同一时间内只能有单一线程获得目标并拥有操作的权利,而 Semaphores 则不是这样,
同一时间内可以有多个线程获得目标并操作!
所以,这里面问大家一个问题,如果还是用信号量的方式去做之前向 CStringArray 中添加节点的同步可以吗?
===================================================
③、Event Objects(事件)
Event 方式是最具弹性的同步机制,因为他的状态完全由你去决定,不会像 Mutex 和 Semaphores 的状态会由类似:
WaitForSingleObject 一类的函数的调用而改变,所以你可以精确的告诉 Event 对象该做什么事?以及什么时候去做!
使用方法:
1、创建一个事件对象:CreateEvent;
2、打开一个已经存在的事件对象:OpenEvent;
3、获得事件的占有权:WaitForSingleObject 等函数(可能造成阻塞);
4、释放事件的占有权(设置为激发(有信号)状态,以让其他等待中的线程苏醒):SetEvent;
5、手动置为非激发(无信号)状态:ResetEvent
6、关闭事件对象句柄:CloseHandle;
固有特点(优点+缺点):
1、是一个系统核心对象,所以有安全描述指针,用完了要 CloseHandle 关闭句柄,这些是内核对象的共同特征;
2、因为是核心对象,所以执行速度稍慢(当然只是相比较而言);
3、因为是核心对象,而且可以命名,所以可以跨进程使用;
4、通常被用于 overlapped I/O 或被用来设计某些自定义的同步对象。
===================================================
//示例代码:
CStringArray g_ArrString;UINT __cdecl ThreadProc(LPVOID lpParameter){int startIdx = (int)lpParameter;for (int idx = startIdx; idx < startIdx+100; ++idx) {CString str;str.Format(_T("%d"), idx);g_ArrString.Add(str);}return 0;}void CThreadTestDlg::OnBnClickedBtn(){for (int idx = 1; idx <= 50; ++idx) {AfxBeginThread(ThreadProc, (LPVOID)(idx*10));}}void CThreadTestDlg::OnBnClickedPrintBtn(){CString strCount;INT_PTR nCount = g_ArrString.GetCount();strCount.Format(_T("%d"), nCount);MessageBox(strCount);for (INT_PTR idx = 0; idx < nCount; ++idx) {OutputDebugString(g_ArrString.GetAt(idx));}}
///////////////////////////////////////////////////////////////////////////////
①、Mutex(互斥器)
使用方法:
1、创建一个互斥器:CreateMutex;
2、打开一个已经存在的互斥器:OpenMutex;
3、获得互斥器的拥有权:WaitForSingleObject、WaitForMultipleObjects 等一类等待的函数……(可能造成阻塞);
4、释放互斥器的拥有权:ReleaseMutex;
5、关闭互斥器:CloseHandle;
HANDLE ghMutex = NULL;CStringArray g_ArrString;UINT __cdecl ThreadProc(LPVOID lpParameter){int startIdx = (int)lpParameter;for (int idx = startIdx; idx < startIdx+100; ++idx) {CString str;str.Format(_T("%d"), idx);DWORD dwWaitResult = WaitForSingleObject(ghMutex, INFINITE);switch (dwWaitResult){case WAIT_ABANDONED:case WAIT_OBJECT_0:g_ArrString.Add(str);ReleaseMutex(ghMutex);break;}//g_ArrString.Add(str);}return 0;}void CThreadTestDlg::OnBnClickedBtn(){ghMutex = CreateMutex(NULL, FALSE, NULL);for (int idx = 1; idx <= 50; ++idx) {AfxBeginThread(ThreadProc, (LPVOID)(idx*10));}}void CThreadTestDlg::OnBnClickedPrintBtn(){CString strCount;INT_PTR nCount = g_ArrString.GetCount();strCount.Format(_T("%d"), nCount);MessageBox(strCount);for (INT_PTR idx = 0; idx < nCount; ++idx) {OutputDebugString(g_ArrString.GetAt(idx));}CloseHandle(ghMutex);}
※ 命名标准:Mutex 可以跨进程使用,所以其名称对整个系统而言是全局的,所以命名不要过于普通,类似:Mutex、Object 等。
最好想一些独一无二的名字等!
固有特点(优点+缺点):
1、是一个系统核心对象,所以有安全描述指针,用完了要 CloseHandle 关闭句柄,这些是内核对象的共同特征;
2、因为是核心对象,所以执行速度会比 Critical Sections 慢几乎100倍的时间(当然只是相比较而言);
3、因为是核心对象,而且可以命名,所以可以跨进程使用;
4、Mutex 使用正确的情况下不会发生死锁;
5、在“等待”一个 Mutex 的时候,可以指定“结束等待”的时间长度;
6、可以检测到当前拥有互斥器所有权的线程是否已经退出!Wait……函数会返回:WAIT_ABANDONED
===================================================
②、Semaphores(信号量)
租车例子的比喻很恰当!
使用方法:
1、创建一个信号量:CreateSemaphore;
2、打开一个已经存在的信号量:OpenSemaphore;
3、获得信号量的一个占有权:WaitForSingleObject、WaitForMultipleObjects 等一类等待的函数……(可能造成阻塞);
4、释放信号量的占有权:ReleaseSemaphore;
5、关闭信号量:CloseHandle;
HANDLE ghSemaphore = NULL;UINT __cdecl ThreadProc(LPVOID lpParameter){int startIdx = (int)lpParameter;CString strOut;while(TRUE) {DWORD dwWaitResult = WaitForSingleObject(ghSemaphore, 0);switch (dwWaitResult){case WAIT_OBJECT_0:strOut.Format(_T("Thread %d: wait succeeded !"), GetCurrentThreadId());OutputDebugString(strOut);ReleaseSemaphore(ghSemaphore, 1, NULL);break;case WAIT_TIMEOUT: strOut.Format(_T("Thread %d: wait timed out !"), GetCurrentThreadId());OutputDebugString(strOut);break; }}return 0;}void CThreadTestDlg::OnBnClickedBtn(){ghSemaphore = CreateSemaphore(NULL, 10, 10, NULL);for (int idx = 1; idx <= 20; ++idx) {AfxBeginThread(ThreadProc, (LPVOID)(idx*10));}}void CThreadTestDlg::OnBnClickedPrintBtn(){CloseHandle(ghSemaphore);}
※ 命名标准:Semaphores 可以跨进程使用,所以其名称对整个系统而言是全局的,所以命名不要过于普通,类似:Semaphore、Object 等
。
最好想一些独一无二的名字等!
固有特点(优点+缺点):
1、是一个系统核心对象,所以有安全描述指针,用完了要 CloseHandle 关闭句柄,这些是内核对象的共同特征;
2、因为是核心对象,所以执行速度稍慢(当然只是相比较而言);
3、因为是核心对象,而且可以命名,所以可以跨进程使用;
4、Semaphore 使用正确的情况下不会发生死锁;
5、在“等待”一个 信号量 的时候,可以指定“结束等待”的时间长度;
6、非排他性的占有,跟 Critical Sections 和 Mutex 不同,这两种而言是排他性占有,
即:同一时间内只能有单一线程获得目标并拥有操作的权利,而 Semaphores 则不是这样,
同一时间内可以有多个线程获得目标并操作!
所以,这里面问大家一个问题,如果还是用信号量的方式去做之前向 CStringArray 中添加节点的同步可以吗?
===================================================
③、Event Objects(事件)
Event 方式是最具弹性的同步机制,因为他的状态完全由你去决定,不会像 Mutex 和 Semaphores 的状态会由类似:
WaitForSingleObject 一类的函数的调用而改变,所以你可以精确的告诉 Event 对象该做什么事?以及什么时候去做!
使用方法:
1、创建一个事件对象:CreateEvent;
2、打开一个已经存在的事件对象:OpenEvent;
3、获得事件的占有权:WaitForSingleObject 等函数(可能造成阻塞);
4、释放事件的占有权(设置为激发(有信号)状态,以让其他等待中的线程苏醒):SetEvent;
5、手动置为非激发(无信号)状态:ResetEvent
6、关闭事件对象句柄:CloseHandle;
固有特点(优点+缺点):
1、是一个系统核心对象,所以有安全描述指针,用完了要 CloseHandle 关闭句柄,这些是内核对象的共同特征;
2、因为是核心对象,所以执行速度稍慢(当然只是相比较而言);
3、因为是核心对象,而且可以命名,所以可以跨进程使用;
4、通常被用于 overlapped I/O 或被用来设计某些自定义的同步对象。
#include <windows.h>#include <stdio.h>#define THREADCOUNT 4 HANDLE ghGlobalWriteEvent; HANDLE ghReadEvents[THREADCOUNT];DWORD WINAPI ThreadProc(LPVOID);void CreateEventsAndThreads(void) { HANDLE hThread; DWORD i, dwThreadID; // Create a manual-reset event object. The master thread sets // this to nonsignaled when it writes to the shared buffer. ghGlobalWriteEvent = CreateEvent( NULL, // default security attributes TRUE, // manual-reset event TRUE, // initial state is signaled TEXT("WriteEvent") // object name ); if (ghGlobalWriteEvent == NULL) { printf("CreateEvent failed (%d)\n", GetLastError()); return; } else if ( GetLastError() == ERROR_ALREADY_EXISTS ) { printf("Named event already exists.\n"); return; } // Create multiple threads and an auto-reset event object // for each thread. Each thread sets its event object to // signaled when it is not reading from the shared buffer. for(i = 0; i < THREADCOUNT; i++) { // Create the auto-reset event ghReadEvents[i] = CreateEvent( NULL, // no security attributes FALSE, // auto-reset event TRUE, // initial state is signaled NULL); // object not named if (ghReadEvents[i] == NULL) { printf("CreateEvent failed (%d)\n", GetLastError()); return; } hThread = CreateThread(NULL, 0, ThreadProc, &ghReadEvents[i], // pass event handle 0, &dwThreadID); if (hThread == NULL) { printf("CreateThread failed (%d)\n", GetLastError()); return; } }}void WriteToBuffer(VOID) { DWORD dwWaitResult, i; // Reset ghGlobalWriteEvent to nonsignaled, to block readers if (! ResetEvent(ghGlobalWriteEvent) ) { printf("ResetEvent failed (%d)\n", GetLastError()); return; } // Wait for all reading threads to finish reading dwWaitResult = WaitForMultipleObjects( THREADCOUNT, // number of handles in array ghReadEvents, // array of read-event handles TRUE, // wait until all are signaled INFINITE); // indefinite wait switch (dwWaitResult) { // All read-event objects were signaled case WAIT_OBJECT_0: // TODO: Write to the shared buffer printf("Main thread writing to the shared buffer...\n"); break; // An error occurred default: printf("Wait error: %d\n", GetLastError()); ExitProcess(0); } // Set ghGlobalWriteEvent to signaled if (! SetEvent(ghGlobalWriteEvent) ) { printf("SetEvent failed (%d)\n", GetLastError()); ExitProcess(0); } // Set all read events to signaled for(i = 0; i < THREADCOUNT; i++) if (! SetEvent(ghReadEvents[i]) ) { printf("SetEvent failed (%d)\n", GetLastError()); return; } }void CloseEvents(){ int i; for( i=0; i < THREADCOUNT; i++ ) CloseHandle(ghReadEvents[i]); CloseHandle(ghGlobalWriteEvent);}void main(){ int i; // TODO: Create the shared buffer // Create the events and THREADCOUNT threads to read from the buffer CreateEventsAndThreads(); // Write to the buffer three times, just for test purposes for(i=0; i < 3; i++) WriteToBuffer(); // Close the events CloseEvents();}DWORD WINAPI ThreadProc(LPVOID lpParam) { DWORD dwWaitResult; HANDLE hEvents[2]; hEvents[0] = *(HANDLE*)lpParam; // thread's read event hEvents[1] = ghGlobalWriteEvent; // global write event dwWaitResult = WaitForMultipleObjects( 2, // number of handles in array hEvents, // array of event handles TRUE, // wait till all are signaled INFINITE); // indefinite wait switch (dwWaitResult) { // Both event objects were signaled case WAIT_OBJECT_0: // TODO: Read from the shared buffer printf("Thread %d reading from buffer...\n", GetCurrentThreadId()); break; // An error occurred default: printf("Wait error: %d\n", GetLastError()); ExitThread(0); } // Set the read event to signaled if (! SetEvent(hEvents[0]) ) { printf("SetEvent failed (%d)\n", GetLastError()); ExitThread(0); } return 1;}
===================================================
0 0
- 线程间的同步机制(2)
- 线程间的同步机制(1)
- 线程间同步的机制
- 线程的同步机制
- 线程的同步机制
- 线程的同步机制
- 线程间同步机制的总结
- 进程线程间的同步机制
- linux下的线程及同步机制(2)
- 线程间同步机制(一)
- linux的线程同步机制
- linux的线程同步机制
- linux的线程同步机制
- Linux的线程同步机制
- linux的线程同步机制
- linux的线程同步机制
- linux的线程同步机制
- 线程的同步机制分析
- 开发者如何提升和推销自己
- CSS选择器详解
- CSDN博客测试
- Struts2在web.xml中配置为“/*”和“*.action,*.jsp”的差别
- oracle 日期格式FM/FX和日期后缀SP/TH/SPTH/THSP
- 线程间的同步机制(2)
- 手把手教你如何获取IOS MAC地址
- 教你如何升级app适配iOS 7
- jquery 显示*天*时*分*秒
- 代码设计规范
- C++中字符串查找
- cora java volume I 学习笔记
- All_Perm
- 创建你自己的 iOS 框架