2.互斥

来源:互联网 发布:淘宝hd 存在登录风险 编辑:程序博客网 时间:2024/06/06 06:52

本文关注的是互斥原语(primitives)。建议您在继续阅读之前先回顾本系列 第 1 部分 中的下列章节:

  • 初始化
  • 进程
  • 线程
  • 共享内存








如下面的 表 1 所示,互斥提供线程间资源的独占访问控制。它是一个简单的锁,只有持有它的线程才可以释放那个互斥。它确保了它们正在访问的共享资源的完整性(最常见的是共享数据),因为在同一时刻只允许一个线程访问它。



<>
Win32 Linux CreateMutex(0, FALSE, 0); pthread_mutex_init(&mutex, NULL)) CloseHandle(mutex); pthread_mutex_destroy(&mutex) WaitForSingleObject(mutex, INFINITE)) pthread_mutex_lock(&mutex) ReleaseMutex(mutex); pthread_mutex_unlock(&mutex)



回页首

在 Win NT/Win2K 中,所有互斥都是递归的。

在 Win32 中,CreateMutex() 为当前进程中的线程提供资料的独占访问控制。此方法让线程可以串行化对进程内资源的访问。创建了互斥句柄(mutual exclusion handle)后,当前进程中的所有线程都可以使用它(见下面的 清单 1)。



<>
< LPCTSTR LPSECURITY_ATTRIBUTES BOOL ) lName lInitialOwner, lMutexAttributes, CreateMutex(>

Linux 使用 pthread 库调用 pthread_mutex_init() 来创建互斥,如下面的 清单 2 所示。



<>
< pthread_mutex_init(pthread_mutex_t>

Linux 有三种类型的互斥。互斥类型决定了在 pthread_mutex_lock 中线程尝试锁定一个它已经持有的互斥时所发生的情形:

Fast mutex:
当尝试使用 pthread_mutex_lock() 去锁定互斥时,进行调用的线程会永远挂起。
Recursive mutex:
pthread_mutex_lock() 立即返回成功返回代码。
Error check mutex:
pthread_mutex_lock() 立即返回错误代码 EDEADLK。

可以以两种方式设置互斥的类型。清单 3 介绍了设置互斥的静态方法。



<>
< * pthread_mutex_t mutexes recursive For mutex="PTHREAD_MUTEX_INITIALIZER;" Fast>

您可以使用这个函数来锁定互斥:pthread_mutex_lock(pthread_mutex_t *mutex)。这个函数会获得一个指向它正在尝试锁定的互斥的指针。当互斥被锁定或者发生错误时,函数返回。那个错误不是归咎于被锁定的互斥。函数会等待互斥被解锁。

设置互斥的另一种方式是使用互斥属性对象。为此,要调用 pthread_mutexattr_init() 来初始化对象,然后调用 pthread_mutexattr_settype() 来设置互斥的类型,如下面的 清单 4 所示。



<>
< int *attr); kind); *attr, pthread_mutexattr_settype(pthread_mutexattr_t pthread_mutexattr_init(pthread_mutexattr_t>

使用下面的函数解开对互斥的锁定(见 清单 5):

这里是创建互斥的示例代码(见下面的 67)。



<>
<>



< Win32 6.>
< } RC_OBJECT_NOT_CREATED; return { mutex; if mutex="CreateMutex(0," (!(mutex)) 0); FALSE,>



< Linux 相应的 7.>
< } RC_OBJECT_NOT_CREATED; return { mutex; pthread_mutex_t if (rc="pthread_mutex_init(&mutex," attr; &attr)) (&attr); pthread_mutexattr_init>




回页首

在 Win32 中,CloseHandle() 方法(见 清单 8)可以删除为当前进程中资源提供独占访问控制的对象。删除那个对象后,那个互斥对象就会无效,直到 CloseHandle() 方法通过调用 CreateMutex 重新初始化它。

当不再对资源进行独占访问后,您应该调用这个方法销毁它。如果您需要放弃那个对象的所有权,那么应该调用 ReleaseMutex() 方法。

在 Linux 中,pthread_mutex_destroy() 会销毁互斥对象,这会释放它可能会持有的资源。它还会检查互斥在那个时刻是不是解除锁定的(见清单 9)。



< Win32 8.>
< return ) CloseHandle(mutex); RC_NOT_OWNER; WAIT_TIMEOUT (DWORD)0)="=">



< Linux 9.>
< return RC_NOT_OWNER; EBUSY) (pthread_mutex_destroy(&mutex)="=">




回页首

在 Win32 中,WaitForSingleObject()(见 清单 10)会阻塞对当前进程内资源的独占访问的请求。进程可以通过下面的方式阻塞请求:

  1. 如果独占访问请求的资源没有被锁定,则这个方法锁定它。
  2. 如果独占访问的资源已经被锁定,则此方法阻塞那个调用线程,直到那个资源被解除锁定。

Linux 使用 pthread_mutex_lock()(见 清单 11)。

您还可以使用 pthread_mutex_trylock() 来测试某个互斥是否已经被锁定,而不需要真正地去锁定它。如果另一个线程锁定了那个互斥,则 pthread_mutex_trylock 将不会阻塞。它会立即返回错误代码 EBUSY。



< Win32 10.>
< return WAIT_FAILED) RC_LOCK_ERROR; INFINITE))="=" ((rc="WaitForSingleObject(mutex,">



< Linux 11.>
< return (rc="pthread_mutex_lock(&mutex))" RC_LOCK_ERROR;>




回页首

Win32 使用 ReleaseMutex()(见 清单 12)来释放对资源的独占访问。如果进行调用的线程并不拥有那个互斥对象,则这个调用可能会失败。

Linux 使用 pthread_mutex_unlock() 来释放或者解锁互斥(见清单 13)。



< Win32 12.>
< } return { rc="GetLastError();" RC_UNLOCK_ERROR; ReleaseMutex(mutex)) (!>



< Linux 13.>
<>




回页首

< SPAN>

这里是获得进程内互斥的 Win32 示例代码(见 Listing 14):



< Win32 14.>
< ); int unsigned } RC_OBJECT_NOT_CREATED; return { * a if( HANDLE mutex; DWORD the Thread be to for by released printf( ) pParam 5 sleeps pParam, %s. blocked WAIT_FAILED) if *pParam void thread_proc( thread ?Main arg1="7;" %d hThrd; *threadId2="(HANDLE)" RC_THREAD_NOT_CREATED); -1) (hThrd="=" 2?); stacksize, NULL, entry of Definition thrdproc, hThrd="_beginthread(" *threadId1="(HANDLE)" 1?); ?Thread stacksize else 8192 < Process ?Intra argv[1] argc arg1; stacksize; *threadId2; *threadId1; **argv char argc, main( executed (function) procedure *data); (void thrdproc <windows.h> #include <stdlib.h> <stdio.h> rc="GetLastError();" ; rc; 0; created. mutex="CreateMutex(0," 0); FALSE, CloseHandle(mutex); RC_NOT_OWNER; WAIT_TIMEOUT (DWORD)0)="=" RC_LOCK_ERROR; INFINITE))="=" ((rc="WaitForSingleObject(mutex," RC_UNLOCK_ERROR; ReleaseMutex(mutex)) (! 1000 5* Sleep( 5*1000 deleted. ?Mutex WaitForSingleObject(mutex, RC_LOCK_ERROR (mutex="=NULL)" Mutex ? blocked. released. n? tMutex test. ?Start. sec. ?Stop. n?, (%lx) t%s>

相应的获得进程内互斥的 Linux 示例代码(见 清单 15):



< Linux 相应的 15.>
< ); ( int } RC_OBJECT_NOT_CREATED; return { * if( NULL)) mutex; pthread_mutex_t for by released printf( ) sleep(5); pParam 5 sleeps pParam, %s. blocked if *pParam void thread_proc( (5); sleep thread ?Main arg1="7;" %d ?Thread else < Process ?Intra argv[1] argc arg1; **argv char argc, main( (void #include <stdlib.h> <stdio.h> rc="0;" (rc="pthread_mutex_lock" ?pthread_mutex_unlock sleep( 0; ?pthread_CREATE )) 2? (void*(*)(void*))thread_proc, &pthread_attr2, ?pthread_attr_setstacksize2 120*1024)) ?pthread_attr_init2 ?pthread_create 1? &pthread_attr, ?pthread_attr_setstacksize ?pthread_attr_init pthread_attr2; pthread_attr_t pthread_attr; threadId2; pthread_t threadId1; attr; pthread_mutexattr_t data); thread_proc <pthread.h> <unistd.h> types.h> <sys nRet created. nRet; RC_LOCK_ERROR; RC_UNLOCK_ERROR; ?Mutex Mutex :pthread_mutex_unlock ? (nRet="pthread_mutex_lock(&mutex))" LOCK ?thread_proc pthread_mutex_destroy(&mutex); sleep(arg1); RC_THREAD_NOT_CREATED; RC_STACKSIZE_ERROR; RC_THREAD_ATTR_ERROR; (&mutex)) NOT &mutex, &attr pthread_mutexattr_init( blocked. released. n? tMutex test. ?Start. sec. ?Stop. n?, (%lx) t%s ERROR2. ERROR.>

这里是获得进程间互斥的另一 Win32 示例代码。

互斥是系统范围内对象,可以由多个进程使用。如果程序 A 创建一个互斥,则程序 B 可以使用同一个互斥。互斥有名称,并且,一个给定名称的互斥在同一机器上同一时刻只能存在一个。如果您创建了一个名为“My Mutex” 的互斥,则任何其他程序都不能使用这个名称创建互斥,如下面的清单 1618 所示。



< 进程间互斥示例代码>
< ); ( int } RC_OBJECT_NOT_CREATED; return { (HANDLE) if( HANDLE mutex; CloseHandle DWORD - printf( ) ! WAIT_FAILED) if OK; Process <windows.h> #include <stdio.h> rc="GetLastError();" rc; WAIT_FOR_ENTER; created. NULL sec_attr.bInheritHandle="TRUE;" sec_attr.lpSecurityDescriptor="NULL;" SECURITY_ATTRIBUTES sec_attr.nLength="sizeof(" test ?Inter sec_attr; main() );getchar() ?Press WAIT_FOR_ENTER #define mutex="CreateMutex(&sec_attr," FALSE, RC_LOCK_ERROR; RC_UNLOCK_ERROR; deleted. ?Mutex WaitForSingleObject(mutex, Mutex (mutex); ReleaseMutex(mutex) INFINITE)="=" Mutex?); ?My blocked. released. n? ?Start. ?Stop. ENTER>

在此,Linux 实现使用的是 System V Interprocess Communications(IPC)函数,如清单 1719 所示。



< 示例代码>
< ); ( value int unsigned RC_OBJECT_NOT_CREATED; return { * if( 0, struct for - printf( ) 1, !="0)" if -1) < Process #include 0; <unistd.h> types.h> <sys WAIT_FOR_ENTER; created. test ?Inter main() );getchar() ?Press WAIT_FOR_ENTER #define IPC_RMID 0 flag="IPC_CREAT;" S_IWGRP; |="S_IRUSR" S_IRGRP S_IWUSR atol( flag; key_t }; stat.h> sem.h> 0) RC_LOCK_ERROR; RC_UNLOCK_ERROR; deleted. ?Mutex Mutex ?My shr_sem, semctl( 1) &semBuf, (semop(shr_sem, semBuf.sem_flg="SEM_UNDO;" semBuf.sem_op="-1;" semBuf.sem_num="0;" arg)="=" SETVAL, (semctl(shr_sem, arg.val="1;" (shr_sem semKey, semget( shr_sem="(int)" RC_INVALID_PARAM; Mutex? semKey="(key_t)" arg; semun union semBuf; sembuf semKey; shr_sem; info IPC buffer __buf; seminfo SETALL GETALL, array *array; short IPC_SET IPC_STAT, *buf; semid_ds SETVAL val; blocked. released. n? ?Start. ?Stop. ENTER>



< 进程间示例代码>
< ); ( 2. int } RC_OBJECT_NOT_CREATED; return { (HANDLE) if( HANDLE mutex; CloseHandle to - printf( ) ! WAIT_FAILED) if OK; Process <windows.h> #include <stdio.h> NULL sec_attr.bInheritHandle="TRUE;" sec_attr.lpSecurityDescriptor="NULL;" SECURITY_ATTRIBUTES sec_attr.nLength="sizeof(" test ?Inter sec_attr; main() closed. ?Try opened. mutex="OpenMutex(MUTEX_ALL_ACCESS," RC_LOCK_ERROR; RC_UNLOCK_ERROR; ?Mutex WaitForSingleObject(mutex, Mutex (mutex); ReleaseMutex(mutex) INFINITE)="=" Mutex?); release blocked. block “My TRUE, released. n? ?Start. ?Stop. mutex. n?);>



< 示例代码>
< ); ( 2. int } RC_OBJECT_NOT_CREATED; return { if( mutex; struct to - printf( ) 1, !="0)" if -1) Process #include <stdio.h> 0; <unistd.h> <sys nRet="0;" test ?Inter main() 0 flag="0;" S_IWGRP; |="S_IRUSR" S_IRGRP S_IWUSR atol( flag; key_t stat.h> sem.h> closed. ?Try mutex="(int)" RC_LOCK_ERROR; RC_UNLOCK_ERROR; ?Mutex (mutex="=" Mutex ?My 1) &semBuf, semBuf.sem_flg="SEM_UNDO;" semBuf.sem_op="-1;" semBuf.sem_num="0;" semKey, semget( RC_INVALID_PARAM; Mutex? semKey="(key_t)" semBuf; sembuf semKey; release blocked. block released. (semop(mutex, opened ipc.h> n? ?Start. ?Stop. mutex. n?);>

原创粉丝点击