90-互斥量的共享属性
来源:互联网 发布:lacoste淘宝是正品吗 编辑:程序博客网 时间:2024/06/02 07:31
用于线程互斥的互斥量也有相应的属性 pthread_mutexattr_t,这里只讨论三个方面:
- 共享属性
- 鲁棒属性
- 互斥量的递归类型
本文先介绍共享属性。
1. 属性的初始化与回收
互斥量属性的数据类型是 pthread_mutexattr_t. 下面两个函数分别用于互斥量属性的初始化与回收。
int pthread_mutexattr_init(pthread_mutexattr_t *attr);int pthread_mutexattr_destroy(pthread_mutexattr_t *attr);
2. 共享属性
除了互斥量有共享属性外,其它的线程互斥同步对象如读写锁、自旋锁、条件变量、屏障都有共享属性。
该属性有两种情况:
PTHREAD_PROCESS_PRIVATE
: 这种是默认的情况,表示互斥量只能在本进程内部使用。PTHREAD_PROCESS_SHARED
:表示互斥量可以在不同进程间使用。
对于第一种情况,我们早已经学会。第二种情况,需要结合前面的进程间通信技术才有用。一般需要在共享内存中分配互斥量,然后再为互斥量指定PTHREAD_PROCESS_SHARED
属性就可以了。
3. 实验
本实验中的程序分为了 4 个部分,分别是 init、destroy、buyticket 和 rbstbuyticket.
init 程序的作用是申请共享内存,并在共享内存中分配互斥量等。
destroy 用来回收共享内存中的互斥量,并销毁共享内存。
buyticket 和 rbstbuyticket 是从共享内存的数据中抢票的。
.|- init.c|- destroy.c|- buyticket.c|- rbstbuyticket.c|- Makefile // Makefile 文件主要用来一次性编译完所有文件。
本部分实验,只用的到前三个程序,最后一个 rbstbuyticket.c 在讲鲁棒属性的时候用的到。
3.1 init.c 程序
程序 init 用来创建一块共享内存,可以给 init 程序传递一个命令行参数,也可以不传。如果传递参数,表示为互斥量指定鲁棒性属性,本文我们先不传递参数。
// init.c#include <unistd.h>#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <sys/ipc.h>#include <sys/shm.h>#include <pthread.h>#define PERR(msg) do { perror(msg); exit(-1); } while(0)#define PPERR(err, msg) do { err = errno; perror(msg); exit(-1); } while(0)struct ticket { int remain; pthread_mutex_t lock;};// 打印共享属性void printshared(pthread_mutexattr_t *attr) { int err, shared; err = pthread_mutexattr_getpshared(attr, &shared); if (err != 0) PPERR(err, "pthread_mutexattr_getshared"); if (shared == PTHREAD_PROCESS_PRIVATE) puts("shared = PTHREAD_PROCESS_PRIVATE"); else if (shared == PTHREAD_PROCESS_SHARED) puts("shared = PTHREAD_PROCESS_SHARED"); else puts("shared = ???");}// 打印鲁棒属性void printrobust(pthread_mutexattr_t *attr) { int err, robust; err = pthread_mutexattr_getrobust(attr, &robust); if (err != 0) PPERR(err, "pthread_mutexattr_getrobust"); if (robust == PTHREAD_MUTEX_STALLED) puts("robust = PTHREAD_MUTEX_STALLED"); else if (robust == PTHREAD_MUTEX_ROBUST) puts("robust = PTHREAD_MUTEX_ROBUST"); else puts("robust = ???");}int main(int argc, char* argv[]) { int err, shared, robust = 0, flag = 1; if (argc >= 2) robust = 1; key_t key = 0x8888; // 创建共享内存 int id = shmget(key, getpagesize(), IPC_CREAT | IPC_EXCL | 0666); if (id < 0) PERR("shmget"); // 挂接共享内存 struct ticket *t = (struct ticket*)shmat(id, NULL, 0); if ((int)t == -1) PERR("shmat"); // 设置余票数量为 5 t->remain = 5; pthread_mutexattr_t mutexattr; err = pthread_mutexattr_init(&mutexattr); if (err != 0) PPERR(err, "pthread_mutexattr_init"); printshared(&mutexattr); printrobust(&mutexattr); // 将互斥量的共享属性设置为可以进程间共享使用。 shared = PTHREAD_PROCESS_SHARED; err = pthread_mutexattr_setpshared(&mutexattr, shared); if (err != 0) PPERR(err, "pthread_mutexattr_setshared"); // 如果有命令行参数,就将鲁棒性设置为 PTHREAD_MUTEX_ROBUST // 本文暂时不设置此值 if (robust) { err = pthread_mutexattr_setrobust(&mutexattr, PTHREAD_MUTEX_ROBUST); if (err != 0) PPERR(err, "pthread_mutexattr_setshared"); } puts("modify attribute ------------------>"); printshared(&mutexattr); printrobust(&mutexattr); pthread_mutex_init(&t->lock, &mutexattr); err = pthread_mutexattr_destroy(&mutexattr); if (err != 0) PPERR(err, "pthread_mutexattr_destroy"); err = shmdt((void*)t); if (err != 0) PERR("shmdt"); return 0;}
3.2 destroy.c
destroy 程序主要用于回收互斥量和共享内存。
#include <unistd.h>#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <sys/ipc.h>#include <sys/shm.h>#include <pthread.h>#define PERR(msg) do { perror(msg); exit(-1); } while(0)#define PPERR(err, msg) do { err = errno; perror(msg); exit(-1); } while(0)struct ticket { int remain; pthread_mutex_t lock;};int main() { int err; key_t key = 0x8888; int id = shmget(key, 0, 0); if (id < 0) PERR("shmget"); struct ticket *t = (struct ticket*)shmat(id, NULL, 0); if ((int)t == -1) PERR("shmat"); err = pthread_mutex_destroy(&t->lock); if (err != 0) PPERR(err, "pthread_mutex_destroy"); err = shmdt((void*)t); if (err != 0) PERR("shmdt"); err = shmctl(id, IPC_RMID, NULL); if (err != 0) PERR("shmctl"); return 0;}
3.3 buyticket.c
buyticket 程序主要用于抢票,该程序需要从命令行传递参数,表示抢票人的名字。比如./buyticket allen
表示抢票人是 allen.
#include <unistd.h>#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <sys/ipc.h>#include <sys/shm.h>#include <pthread.h>#define PERR(msg) do { perror(msg); exit(-1); } while(0)#define PPERR(err, msg) do { err = errno; perror(msg); exit(-1); } while(0)struct ticket { int remain; pthread_mutex_t lock;};int main(int argc, char* argv[]) { if (argc < 2) { printf("Usage: %s <name>\n", argv[0]); exit(-1); } char *name = argv[1]; int err, shared, flag = 1; key_t key = 0x8888; int id = shmget(key, 0, 0); if (id < 0) PERR("shmget"); struct ticket *t = (struct ticket*)shmat(id, NULL, 0); if ((int)t == -1) PERR("shmat"); // 只要票数大于 0 就不断抢票。 while(flag) { pthread_mutex_lock(&t->lock); int remain = t->remain; if (remain > 0) { sleep(1); printf("%s buy a ticket\n", name); --remain; sleep(3); t->remain = remain; } else flag = 0; pthread_mutex_unlock(&t->lock); sleep(2); } err = shmdt((void*)t); if (err != 0) PERR("shmdt"); return 0;}
3.4 编译——Makefile 文件
此文件可以方便程序编译。
main:init destroy buyticketinit:init.c gcc init.c -o init -lpthreaddestroy:destroy.c gcc destroy.c -o destroy -lpthreadbuyticket:buyticket.c gcc buyticket.c -o buyticket -lpthread
注意,上面所有以 gcc 开头的行前面是个 tab 符号,即按下键盘上的 Tab 键所产生的,千万不能是空格。
完成些文件后,保存退出,然后在命令行键入
$ make
此时就会产生三个程序:init、destroy 和 buyticket
3.5 运行
- 初始化
./init
- 开启两个进程进行抢票
开启两个终端假设为终端 A 和终端 B. 在终端 A 中键入
./buyticket allen
终端 B 中键入
./buyticket luffy
记住这两个进程在执行时间上不能差的太远,别等到其中一个运行结束才开始另一个。
- 运行结果
图1 运行结果
可以从图 1 中看到,一共有 5 张票,分别被两个不同进程中的线程所抢到,其中 allen 抢了 3 张票,而 luffy 抢了 2 张票。
完成了上面的程序的执行后,别忘记使用 ./destroy
对共享内存进行回收。
4. 总结
- 掌握互斥量的共享属性
- 掌握共享内存的使用
练习:上面的程序中,当 allen 抢到第 2 张票后,立即按下 CTRL + C 中断进程,会有什么后果?
- 90-互斥量的共享属性
- 共享的 HTML 控件属性
- 属性中共享不见的解决办法
- Spring mvc 中属性的共享
- 找出共享同一属性的所有元素
- cortex-m3中存储器的访问属性中的共享属性
- Linux线程互斥量--进程共享属性
- linux线程属性、共享属性
- 修改类的静态成员的共享属性
- 3.1 共享属性
- iOS 用Protocol 给类加共享的属性
- 2把共享的属性方法移动到prototype上
- 写到prototype里的属性什么时候各实例共享值,什么时候不共享?
- 命令行设置属性和共享
- android中一个activity的属性在所有的activity中共享
- 从对象创建 到构造函数以及原型对象(prototype的使用,属性的共享)
- 实现Runnable接口的多线程可以实现属性共享的原因
- Thread 和 Runnable创建新线程的区别,Runnable可以共享线程类的实例属性
- Qt+opencv+matlab opencv读写高光谱 .mat文件
- 【Java】运算符
- 集合
- Echarts入门
- 浅谈JavaScript中树的先序、中序、后序遍历
- 90-互斥量的共享属性
- MPAndroidChart bar宽度固定且可左右滑动
- Mybatis
- 信息检索
- hadoop学习的第二天---配置Hadoop环境(少走弯路,详细教程)
- 迷茫<第一篇:初到北京>
- 阿里暑期实习一面总结
- JAVA基础
- JAVA常用工具收集总结