品牌推广网站如何做,wordpress2018,seo网站推广经理招聘,网站建设算不算固定资产递归锁的递归特性确实只是对于持有锁的线程。当一个线程获取了递归锁后#xff0c;它可以多次重复获取该锁#xff0c;而不会导致自身阻塞或死锁。这是递归锁的重要特点#xff0c;它允许同一个线程在已经持有锁的情况下#xff0c;再次获取相同的锁。
然而#xff0c;对…递归锁的递归特性确实只是对于持有锁的线程。当一个线程获取了递归锁后它可以多次重复获取该锁而不会导致自身阻塞或死锁。这是递归锁的重要特点它允许同一个线程在已经持有锁的情况下再次获取相同的锁。
然而对于其他线程如果该递归锁已经被某个线程持有即使是持有锁的线程自身多次获取的那么其他线程在尝试获取该锁时仍然会被阻塞直到持有锁的线程进行了相应次数的解锁操作使得锁完全释放后其他线程才有机会获取该锁。
递归锁通常应用于递归函数或方法以及存在嵌套临界区的情况。在这些场景下同一个线程可能需要在不同的递归层次或嵌套的临界区中多次获取同一个锁。通过使用递归锁可以确保线程不会因为自身重复获取锁而产生死锁问题。
需要注意的是使用递归锁时持有锁的线程必须进行相应次数的解锁操作以平衡之前的加锁操作。也就是说对于每次加锁都需要有一个对应的解锁只有当解锁次数与加锁次数相等时锁才会完全释放其他线程才能获取该锁。如果解锁次数不足或过多都可能导致死锁或其他同步问题的发生。
如在一个递归函数中每次递归调用都需要获取相同的锁进行保护递归锁就可以满足这种需求。而如果使用普通的互斥锁在同一线程中再次尝试获取已经持有的锁时就会导致死锁。 PTHREAD_MUTEX_RECURSIVE 是一种递归锁它允许同一个线程对同一个锁成功获得多次并通过多次 unlock 解锁。
使用 PTHREAD_MUTEX_RECURSIVE 递归锁的一般步骤如下
包含必要的头文件#include pthread.h。初始化互斥锁属性对象使用 pthread_mutexattr_init(attr); 初始化一个互斥锁属性对象 attr。设置锁的类型为递归锁通过 pthread_mutexattr_settype(attr, pthread_mutex_recursive); 将互斥锁的类型设置为递归锁。初始化递归锁使用 pthread_mutex_init(mutex, attr); 初始化递归锁 mutex并关联之前设置好属性的 attr 对象。在需要加锁的代码段前加锁通过 pthread_mutex_lock(mutex); 进行加锁操作。如果是在同一个线程中且之前已经加过锁不会产生死锁而是可以成功再次加锁。在相应的代码段结束后解锁调用 pthread_mutex_unlock(mutex); 释放锁。需要注意的是加锁几次就需要解锁几次才能完全释放该锁以便其他线程获取该锁。不再使用递归锁后销毁互斥锁使用 pthread_mutex_destroy(mutex); 释放锁资源。 下面是一个简单的示例代码演示了递归锁的使用
#includepthread.h
#includestdio.h
#includestring.h
#includestdlib.hpthread_mutex_t mutex;
pthread_mutexattr_t attr;void*func(void*arg){if(*(char*)arg\0) return NULL;pthread_mutex_lock(mutex); // 加锁char*str (char*)arg;while(*str!\0){fputc(*str, stdout);str;}fputc(\n, stdout);func((char*)arg 1); // 递归调用自身再次加锁pthread_mutex_unlock(mutex); // 解锁return NULL;
}int main()
{int ret;if((retpthread_mutexattr_init(attr))!0){ // 初始化互斥锁属性对象fprintf(stderr, create mutex attribute error.msg:%s, strerror(ret));exit(1);}pthread_mutexattr_settype(attr, pthread_mutex_recursive); // 设置为递归锁属性pthread_mutex_init(mutex, attr); // 初始化递归锁pthread_t p1, p2;char str1[8], str2[8];sprintf(str1, abcdefg);sprintf(str2, 1234567);if((retpthread_create(p1, NULL, func, str1))!0){ // 创建线程 p1 并执行 func 函数fprintf(stderr, create thread error.msg:%s, strerror(ret));exit(1);}if((retpthread_create(p2, NULL, func, str2))!0){ // 创建线程 p2 并执行 func 函数fprintf(stderr, create thread error.msg:%s, strerror(ret));exit(1);}pthread_join(p1, NULL); // 等待线程 p1 结束pthread_join(p2, NULL); // 等待线程 p2 结束
}在上述示例中func 函数中存在递归调用并且在递归调用时会再次对同一个锁进行加锁操作。如果使用普通的互斥锁非递归锁则会导致死锁。而使用 PTHREAD_MUTEX_RECURSIVE 递归锁就可以在同一个线程中多次加锁而不会产生死锁。
需要注意的是虽然递归锁提供了方便但也应该谨慎使用尽量避免在不必要的情况下过度使用递归锁因为它可能会导致一些难以察觉的逻辑错误或性能问题。在实际编程中确保正确地管理锁的获取和释放次数以避免出现意外的情况。另外在使用完递归锁后记得使用 pthread_mutex_destroy 函数销毁锁以释放相关资源。 在POSIX标准中递归互斥锁的类型通常被定义为PTHREAD_MUTEX_RECURSIVE。但是在一些GNU系统如LinuxPTHREAD_MUTEX_RECURSIVE常被定义为PTHREAD_MUTEX_RECURSIVE_NP其中NP代表“Non-Portable”非可移植的。
具体来说
PTHREAD_MUTEX_RECURSIVEPOSIX标准定义的递归互斥锁类型。这在POSIX兼容的系统中应该可以直接使用。PTHREAD_MUTEX_RECURSIVE_NPGNU特定的递归互斥锁类型。在一些GNU系统中这个宏定义被用来替代标准的PTHREAD_MUTEX_RECURSIVE。
通常POSIX兼容系统如现代的Linux发行版应该支持PTHREAD_MUTEX_RECURSIVE。但是如果你的系统使用了较旧的或特定的GNU库版本你可能需要使用PTHREAD_MUTEX_RECURSIVE_NP。
检查和使用合适的宏
为了编写兼容性更好的代码可以在编译时检查是否定义了PTHREAD_MUTEX_RECURSIVE并根据需要使用适当的宏。例如
#include pthread.hint main() {pthread_mutexattr_t attr;pthread_mutexattr_init(attr);#ifdef PTHREAD_MUTEX_RECURSIVEpthread_mutexattr_settype(attr, PTHREAD_MUTEX_RECURSIVE);
#elsepthread_mutexattr_settype(attr, PTHREAD_MUTEX_RECURSIVE_NP);
#endif// 其余代码...pthread_mutexattr_destroy(attr);return 0;
}定义_GNU_SOURCE
在包含pthread.h之前定义_GNU_SOURCE宏也可以启用所有GNU扩展功能确保PTHREAD_MUTEX_RECURSIVE宏被正确识别
#define _GNU_SOURCE
#include pthread.h// 其余代码...