企业网站模板趋势,wordpress配置支付宝,女教师网课入侵录屏 ,大连市营商环境建设局门户网站多线程之线程同步Mutex #xff08;功能与Critial Sections相同#xff0c;但是属于内核对象#xff0c;访问速度较慢#xff0c;可以被不同进程调用#xff09; 一 Mutex 互斥
对象#xff08;mutex#xff09;内核对象能够确保线程拥有对单个资源的互斥访问权。实际上…多线程之线程同步Mutex 功能与Critial Sections相同但是属于内核对象访问速度较慢可以被不同进程调用 一 Mutex 互斥
对象mutex内核对象能够确保线程拥有对单个资源的互斥访问权。实际上互斥对象是因此而得名的。互斥对象包含一个使用数量 一个线程ID和一个递归计数器。 互斥对象的行为特性与关键代码段相同但是互斥对象属于内核对象而关键代码段则属于用户方式对象。这意味着互斥对象的运行速度比关键代码段要慢。但是这也意味
着不同进程中的多个线程能够访问单个互斥对象并且这意味着线程在等待访问资
源
时可以设定一个超时
值。 ID用于标识系统中的哪个线程当前拥有互斥对象递归计数器用于指明该线程拥有互斥对象的次数。 互斥对象有许多用途属于最常用的内核对象之一。通常来说它们用于保护由多个线程访问的内存块。如果多个线程要同时访问内存块内存块中的数据就可能遭到破坏。互斥对象能够保证访问内存块的任何线程拥有对该内存块的独占访问权这样就能够保证数据的完整性。 互斥对象的使用规则如下 ? 如果线程ID是0这是个无效ID互斥对象不被任何线程所拥有并且发出该互斥对象的通知信号。 ? 如果ID是个非0数字那么一个线程就拥有互斥对象并且不发出该互斥对象的通知信号。 ? 与所有其他内核对象不同 互斥对象在操作系统中拥有特殊的代码允许它们违反正常的规则。 若要使用互斥对象必须有一个进程首先调用CreateMutex以便创建互斥对象 HANDLECreateMutex( PSECURITY_ATTRIBUTES psa, BOOL fInitialOwner, PCTSTR pszName); InitialOwner参数用于控制互斥对象的初始状态。如果传递FALSE这是通常情况下传递的值那么互斥对象的ID和递归计数器均被设置为0。这意味着该互斥对象没有被任何线程所拥有因此要发出它的通知信号。 如果为fInitialOwner参数传递TRUE那么该对象的线程ID被设置为调用线程的ID递归计数器被设置为1。由于ID是个非0数字因此该互斥对象开始时不发出通知信号。 通过调用一个等待函数并传递负责保护资源的互斥对象的句柄线程就能够获得对共享资源的访问权。在内部等待函数要检查线程的ID以了解它是否 是0互斥对象发出通知信号。如果线程ID是0那么该线程ID被设置为调用线程的ID递归计数器被设置为1同时调用线程保持可调度状态。 如果等待函数发现ID不是0不发出互斥对象的通知信号那么调用线程便进入等待状态。系统将记住这个情况并且在互斥对象的ID重新设置为0 时将线程ID设置为等待线程的ID将递归计数器设置为1并且允许等待线程再次成为可调度线程。与所有情况一样对互斥内核对象进行的检查和修改都是 以原子操作方式进行的。 一旦线程成功地等待到一个互斥对象该线程就知道它已经拥有对受保护资源的独占访问权。试图访问该资源的任何其他线程通过等待相同的互斥对象均 被置于等待状态中。当目前拥有对资源的访问权的线程不再需要它的访问权时它必须调用ReleaseMutex函数来释放该互斥对象 BOOL ReleaseMutex(HANDLE hMutex); 该函数将对象的递归计数器递减1。 当该对象变为已通知状态时系统要查看是否有任何线程正在等待互斥对象。如果有系统将“按公平原则”选定等待线程中的一个为它赋予互斥对象的所 有权。当然这意味着线程I D被设置为选定的线程的ID并且递归计数器被置为1。如果没有其他线程正在等待互斥对象那么该互斥对象将保持已通知状态这样等待互斥对象的下一个 线程就立即可以得到互斥对象。 二 API
Mutex functionDescription CreateMutex Creates or opens a named or unnamed mutex object. CreateMutexEx Creates or opens a named or unnamed mutex object and returns a handle to the object. OpenMutex Opens an existing named mutex object. ReleaseMutex Releases ownership of the specified mutex object. 三 实例 来自msdn的实例在线程函数中有一个循环 在每个循环的开始都取得Mutex然后
对全局或静态操作
相当于在关键代码段操作然后在使用完以后释放它
大家可以执行查
看结果
。 #include windows.h #include stdio.h #define THREADCOUNT 64 // less than 64 HANDLE ghMutex; int g_x 0 ; DWORD WINAPI WriteToDatabase(LPVOID); void main() { HANDLE aThread[THREADCOUNT]; DWORD ThreadID; int i; // Create a mutex with no initial owner ghMutex CreateMutex( NULL, // default security attributes FALSE, // initially not owned NULL); // unnamed mutex if (ghMutex NULL) { printf(CreateMutex error: %d\n, GetLastError()); return; } // Create worker threads for( i0; i THREADCOUNT; i ) { aThread[i] CreateThread( NULL, // default security attributes 0, // default stack size (LPTHREAD_START_ROUTINE) WriteToDatabase, NULL, // no thread function arguments 0, // default creation flags ThreadID); // receive thread identifier if( aThread[i] NULL ) { printf(CreateThread error: %d\n, GetLastError()); return; } } // Wait for all threads to terminate WaitForMultipleObjects(THREADCOUNT, aThread, TRUE, INFINITE); // Close thread and mutex handles for( i0; i THREADCOUNT; i ) CloseHandle(aThread[i]); CloseHandle(ghMutex); printf(g_x is :%d\n,g_x); } DWORD WINAPI WriteToDatabase( LPVOID lpParam ) { DWORD dwCount0, dwWaitResult; // Request ownership of mutex. while( dwCount 100 ) { dwWaitResult WaitForSingleObject( ghMutex, // handle to mutex INFINITE); // no time-out interval switch (dwWaitResult) { // The thread got ownership of the mutex case WAIT_OBJECT_0: __try { g_x; // TODO: Write to the database printf(Thread %d writing to database\n, GetCurrentThreadId()); dwCount; } __finally { // Release ownership of the mutex object if (! ReleaseMutex(ghMutex)) { // Deal with error. } } break; // The thread got ownership of an abandoned mutex case WAIT_ABANDONED: return FALSE; } } return TRUE; }