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 中断进程,会有什么后果?

0 0
原创粉丝点击