线程同步:Mutex

来源:互联网 发布:设计模式java面试 编辑:程序博客网 时间:2024/06/09 18:51

互斥体实现了“互相排斥”(mutual exclusion)同步的简单形式(所以名为互斥体(mutex))。互斥体禁止多个线程同时进入受保护的代码“临界区”(critical section)。因此,在任意时刻,只有一个线程被允许进入这样的代码保护区。任何线程在进入临界区之前,必须获取(acquire)与此区域相关联的互斥体的所有权。如果已有另一线程拥有了临界区的互斥体,其他线程就不能再进入其中。这些线程必须等待,直到当前的属主线程释放(release)该互斥体。什么时候需要使用互斥体呢?互斥体用于保护共享的易变代码,也就是,全局或静态数据。这样的数据必须通过互斥体进行保护,以防止它们在多个线程同时访问时损坏。

 

The CreateMutex function creates or opens a named or unnamed mutex object.
HANDLE CreateMutex(
  LPSECURITY_ATTRIBUTES lpMutexAttributes,  // SD
  BOOL bInitialOwner,                       // initial owner
  LPCTSTR lpName                            // object name
);

其中参数

①lpMutexAttributes用来设定Mutex对象的安全描述符和是否允许子进程继承句柄。如果lpMutexAttributes 值是NULL, 则句柄不可以被继承。
②bInitialOwner表明是否将Mutex的持有者设置为调用线程。

③lpName参数设置Mutex的名字,该名字区分大小写并不能包含"/",最大长度为MAX_PATH,可设置为NULL表明该Mutex为匿名对象。

如果调用成功,则返回Mutex的句柄,否则返回NULL,如果lpName不为NULL且调用前同名的Mutex已被创建,则返回同名Mutex的句柄,此时调用GetLastError将返回ERROR_ALREADY_EXISTS,参数bInitialOwner将被忽略。

还可以调用OpenMutex打开创建的非匿名Mutex,原型如下

HANDLE OpenMutex(
  DWORD dwDesiredAccess,
  BOOL bInheritHandle,
  LPCTSTR lpName
);

在成功创建或打开Mutex后,可以使用wait functions来等待并获取Mutex的持有权。

转载(有改动):
Mutex物件的做法与特性如下:
  使用CreateMutex()来产生一个Mutex物件,而传入的Mutex名称字串用以区别不同的Mutex,也就是说,不管是哪个Process/Thread,只要传入的名称叁数是相同的一个字串,那CreateMutex()传回值(hMutex, handle of Mutex)会指向相同的一个Mutex物件。这和Event物件相同。然而Mutex和Event有很大的不同,Mutex有Owner的概念,如果Mutex为ThreadA所拥有,那麽ThreadA执行WaitForSingleObject()时,并不会停下来,而会立即传回WAIT_OBJECT_0,而其他的Thread执行WaitForSingleObject()则会停下来,直到Mutex的所有权被Release出来或Time Out。而Thread如何取得Mutex的所有权呢?主要如下:

  1.CreateMutex(Byval 0, 1, "MyMutex") 第二个叁数传1进去,则第一个呼叫CreateMutex且第二个叁数传1的Thread会拥有该Mutex。但如果第二个叁数传0进去,那代表CreateMutex时,没有人拥有该Mutex。
  2.承上的说明,如果Mutex没有拥有者,则第一个呼叫WaitForSingleObject的Thread会拥有该Mutex。

 上面说过,只有拥有该Mutex的Thread在执行WaitForSingleObject()不会停下来,其他的Thread则会停下来,那其他的Thread如何取得该Mutex的所有权呢?那必需是原先拥有该Mutex的Thread以ReleaseMutex来放弃所有权,一旦所有权放出来,而有其他的Thread处於WaitForSingleObject()的停留等待状态,则有一个Thread会即时取得该Mutex的所有权(上面第2点的说明),所以,若其他的Thread也执行WaitForSingleObject()时,就会处於等待的状态。正因WaitForSingleObject()会令Mutex处於UnSignal的状态(和Event不同),所以可以完成同一时问只有一个thread来UpDate共用记忆体的需求(当然大家都要使用Mutex的规则来做,即想Update时,要使用WaitForSingleObject()来看看是否可取得Mutex的所
有权。)

  另有一件事要特别提出,如果一个Thread已取得Mutex的所有权,而它呼叫WaitForSingleObject()
n 次,则也要使用ReleaseMutex n次才能够将Mutex的拥有权放弃,这和Event也不同,而且,非Mutex拥有者呼叫ReleaseMutex也不会有任何作用。而每次以WaitForSingleObject呼叫一次,Mutex会有一个计数器会加一,ReleaseMutex成功会减一,直到Mutex的计数器为0之後,系统才会将之去除。

 

应用实例:

#include <windows.h>

  #include <stdio.h>

  #define THREADCOUNT 2

  HANDLE ghMutex;

  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( i=0; 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( i=0; i < THREADCOUNT; i++ )

  CloseHandle(aThread[i]);

  CloseHandle(ghMutex);

  }

  DWORD WINAPI WriteToDatabase( LPVOID lpParam )

  {

  DWORD dwCount=0, dwWaitResult;

  // Request ownership of mutex.

  while( dwCount < 20 )

  {

  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 {

  // TODO: Write to the database

  printf("Thread %d writing to database.../n",

  GetCurrentThreadId());

  dwCount++;

  }

  __finally {

  // Release ownership of the mutex object

  if (! ReleaseMutex(ghMutex))

  {

  // Handle error.

  }

  }

  break;

  // The thread got ownership of an abandoned mutex

  // The database is in an indeterminate state

  case WAIT_ABANDONED:

  return FALSE;

  }

  }

  return TRUE;

  }

原创粉丝点击