92-递归型互斥量
来源:互联网 发布:mysql体系结构 编辑:程序博客网 时间:2024/06/07 06:51
互斥量的类型属性通常有四种:
PTHREAD_MUTEX_NORMAL
PTHREAD_MUTEX_ERRORCHECK
PTHREAD_MUTEX_RECURSIVE
PTHREAD_MUTEX_DEFAULT
其中第一种和第四种一般都是一样的,宏定义的值相同,是默认情况。第二种提供错误检查。第三种是我们本文需要讨论的。
1. 相关函数
可以使用下面的函数对互斥量的类型属性进行设置和获取:
int pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *type);int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type);
2. 递归类型的互斥量
一般情况下,我们在同一个线程中对同一个互斥量加两次锁,就会死锁。如果将互斥量类型属性设置为递归类型 PTHREAD_MUTEX_RECURSIVE
就不会出现此问题。
递归互斥量内部维护着一个计数器,当互斥量未上锁时,计数器值为 0。只有计数器为 0 的情况下,线程才能够获得锁。只有获得锁的线程,才能持续对互斥量加锁,每加一次锁,计数器的值加 1,每解一次锁,计数器的值减 1.
3. 实验
程序 recsig 的功能是在信号处理函数内部对余票数量加 1. 操作余票的时候,需要加锁。recsig 程序可以从命令行接受一个参数,表示使用递归互斥量,如果不传参数,表示使用普通互斥量。
resig 函数注册了两种信号,第一种是 SIGUSR1,另一种是 SIGINT。当程序启动的时候,会自己给自己发送 SIGUSR1 信号。
3.1 代码
#include <unistd.h>#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <signal.h>#include <pthread.h>#define PPERR(err, msg) do { errno = err; perror(msg); exit(-1); } while(0)struct ticket { int remain; pthread_mutex_t lock;};struct ticket t;void printtype(pthread_mutexattr_t *attr) { int err, type; char *s = "???"; err = pthread_mutexattr_gettype(attr, &type); if (err != 0) PPERR(err, "pthread_mutexattr_gettype"); if (type == PTHREAD_MUTEX_NORMAL) { s = "PTHREAD_MUTEX_NORMAL"; printf("MUTEX TYPE = %s\n", s); } if (type == PTHREAD_MUTEX_ERRORCHECK) { s = "PTHREAD_MUTEX_ERRORCHECK"; printf("MUTEX TYPE = %s\n", s); } if (type == PTHREAD_MUTEX_RECURSIVE) { s = "PTHREAD_MUTEX_RECURSIVE"; printf("MUTEX TYPE = %s\n", s); } if (type == PTHREAD_MUTEX_DEFAULT) { s = "PTHREAD_MUTEX_DEFAULT"; printf("MUTEX TYPE = %s\n", s); }}void setrecursive(pthread_mutexattr_t *attr) { int err, type; type = PTHREAD_MUTEX_RECURSIVE; err = pthread_mutexattr_settype(attr, type); if (err != 0) PPERR(err, "pthread_mutexattr_settype");}void handler(int sig) { if (sig == SIGUSR1) puts("receive SIGUSR1"); else if (sig == SIGINT) puts("receive SIGINT"); pthread_mutex_lock(&t.lock); printf("%s enter handler\n", sig == SIGUSR1 ? "SIGUSR1":"SIGINT"); t.remain++; sleep(3); printf("%s exit handler\n", sig == SIGUSR1 ? "SIGUSR1":"SIGINT"); pthread_mutex_unlock(&t.lock);}int main(int argc, char* argv[]) { int recursive = 0; if (argc >= 2) recursive = 1; t.remain = 3; pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); printtype(&attr); if (recursive == 1) { puts("modify type --------------------->"); setrecursive(&attr); printtype(&attr); } pthread_mutex_init(&t.lock, &attr); pthread_mutexattr_destroy(&attr); signal(SIGUSR1, handler); signal(SIGINT, handler); puts("send SIGUSR1"); kill(getpid(), SIGUSR1); pthread_mutex_destroy(&t.lock); printf("remain = %d\n", t.remain); return 0;}
3.2 编译和运行
- 编译
$ gcc recsig.c -o recsig -lpthread
- 不带参数运行
$ ./recsig
当进入信号处理函数的时候,按下 CTRL+ C,接下来,程序死锁。原因在于信号处理函数在执行的时候,收到了 SIGINT 信号,又加了一次锁,注意它们都属于同一个线程,所以导致了死锁。
图1 普通类型互斥量运行结果
- 带参数运行
$ ./recsig 1
当进入信号处理函数的时候,按下 CTRL+ C,程序正常执行完成。
图2 递归类型互斥量运行结果
4. 总结
- 理解递归类型互斥量的作用
- 信号处理函数中,避免使用互斥量,如果确实要使用,使用递归类型互斥量
0 0
- 92-递归型互斥量
- 递归
- 递归
- 递归
- 递归
- 递归
- 递归
- 递归
- 递归
- 递归
- 递归
- 递归
- 递归
- 递归
- 递归
- 递归
- 递归
- 递归
- android 命名规范
- 编译facebook/folly报错libgflags invalid
- FFmpeg的编译
- Linux面试题集锦四
- 工具开发Servlet动态资源
- 92-递归型互斥量
- OpenCV Python教程(1、图像的载入、显示和保存)
- 叠放箱子问题
- 1. performMeasure
- springMVC文件的上传与下载
- ubuntu Hadoop 填坑记
- mysql 存储过程动态sql
- http请求
- Mac系统终端命令行不执行命令 总出现command not found解决方法