快捷搜索:
来自 67677新澳门手机版 2019-11-05 16:48 的文章
当前位置: 67677新澳门手机版 > 67677新澳门手机版 > 正文

Linux进度间通讯

那篇小说将陈说别意气风发种进度间通讯的机制——频限信号量。注意请不要把它与在此之前所说的连续信号混淆起来,连续信号与时限信号量是莫衷一是的二种东西。有关非数字信号的更加多内容,可以翻阅小编的另意气风发篇小说:[Linux进度间通讯

信号](

后生可畏、什么是能量信号量

为了幸免现身因八个程序同时做客八个分享财富而引发的风度翩翩种类主题素材,大家要求风流罗曼蒂克种办法,它能够透过改造并利用令牌来授权,在任有时刻只可以有一个施行线程访问代码的临界区域。临界区域是指奉行多少更新的代码需求独自占领式地推行。而实信号量就足以提供这么的大器晚成种访谈机制,让叁个临界区同时唯有四个线程在拜谒它,也等于说时限信号量是用来调协进度对共享能源的会见的。

时限信号量是贰个奇特的变量,程序对其访谈都以原子操作,且只允许对它进行等待(即P(时域信号变量))和殡葬(即V(功率信号变量))音信操作。最简便易行的功率信号量是只好取0和1的变量,那也是复信号量最布满的风华正茂种格局,叫做二进制能量信号量。而能够取多少个正整数的实信号量被称为通用时限信号量。这里关键探讨二进制时域信号量。

二、信号量的劳作规律

是因为实信号量只可以进展二种操作等待和出殡和安葬功率信号,即P(sv)和V(sv),他们的行为是如此的:

P(sv):若是sv的值超出零,就给它减1;倘诺它的值为零,就挂起该进程的实行

V(sv):假设有别的进度因等待sv而被挂起,就让它过来运维,若无经过因等待sv而挂起,就给它加1.

比方,正是八个经过分享连续信号量sv,风流洒脱旦中间三个经过奉行了P(sv)操作,它将获取信号量,并得以进去临界区,使sv减1。而第一个进度将被截留步入临界区,因为当它打算推行P(sv)时,sv为0,它会被挂起以伺机第一个进度离开临界区域并实行V(sv)释放时域信号量,这个时候第叁个经过就足以还原试行。

三、Linux的功率信号量机制

Linux提供了生龙活虎组精心设计的时限信号量接口来对功率信号进行操作,它们不可是指向性二进制复信号量,下边将会对这一个函数实行介绍,但请介意,这几个函数都以用来对成组的数字信号量值进行操作的。它们证明在头文件sys/sem.h中。

1、semget()函数

它的效果与利益是开创三个新功率信号量或获得二个本来就有时域信号量,原型为:

int semget(key_t key, int num_sems, int sem_flags);

率先个参数key是整数值(唯意气风发非零卡塔尔,不相干的进度能够通过它访谈贰个时域信号量,它象征前后相继恐怕要动用的有个别能源,程序对具有非频限信号量的寻访都是直接的,程序先经过调用semget()函数并提供二个键,再由系统生成三个一呼百应的实信号标识符(semget()函数的再次来到值卡塔 尔(英语:State of Qatar),独有semget()函数才间接利用复信号量键,全体其余的非确定性信号量函数使用由semget()函数重回的时限信号量标记符。假如四个程序选用同后生可畏的key值,key将负责和谐职业。

其次个参数num_sems钦点须要的能量信号量数目,它的值大致总是1。

其四个参数sem_flags是生龙活虎组标记,当想要当复信号量不设一时创建多个新的复信号量,能够和值IPC_CREAT做按位或操作。设置了IPC_CREAT标识后,就算付出的键是二个本来就有非确定性信号量的键,也不会发出错误。而IPC_CREAT | IPC_EXCL则足以创制一个新的,唯生龙活虎的频限信号量,假如时域信号量已存在,再次回到三个错误。

semget()函数成功重回多少个一倡百和随机信号标记符(非零卡塔尔,退步再次回到-1.

2、semop()函数

它的成效是改造能量信号量的值,原型为:

int semop(int sem_id, struct sembuf *sem_opa, size_t num_sem_ops);

sem_id是由semget()重临的时限信号量标志符,sembuf结构的概念如下:

struct sembuf{
    short sem_num; // 除非使用一组信号量,否则它为0
    short sem_op;  // 信号量在一次操作中需要改变的数据,通常是两个数,一个是-1,即P(等待)操作,
                   // 一个是 1,即V(发送信号)操作。
    short sem_flg; // 通常为SEM_UNDO,使操作系统跟踪信号,
                   // 并在进程没有释放该信号量而终止时,操作系统释放信号量
};

3、semctl()函数

该函数用来直接调节时域信号量音信,它的原型为:

int semctl(int sem_id, int sem_num, int command, ...);

即使有第3个参数,它平日是叁个union semum结构,定义如下:

union semun {
    int val;
    struct semid_ds *buf;
    unsigned short *arry;
};

前多少个参数与前方二个函数中的同样,command经常是下面四个值中的此中一个

SE电视AL:用来把实信号量带头化为一个已知的值。p 那一个值通过union semun中的val成员设置,其功用是在功率信号量第三回使用前对它实行安装。

IPC_RMID:用于删除叁个大器晚成度无需继续接受的信号量标记符。

四、进程使用连续信号量通讯

上面采纳二个例证来证实经过间怎么着利用功率信号量来开展通讯,这么些例子是五个类似的前后相继同一时候向显示屏输出数据,大家得以见到如何利用时域信号量来使多个过程和睦职业,使同不时候只有叁个历程可以向显示器输出数据。注意,要是程序是首先次被调用(为了分化,第三次调用程序时带三个要出口到显示屏中的字符作为三个参数卡塔 尔(英语:State of Qatar),则要求调用set_semvalue()函数开始化时限信号并将message字符设置为传送给程序的参数的首先个字符,同期率先个运行的长河还肩负频限信号量的删减专门的工作。倘诺不删除随机信号量,它将延续在系统中留存,纵然程序已经脱离,它也许在您下一次运作此程序时引发难题,何况实信号量是黄金时代种轻松的能源。

在main函数中调用semget()来创制三个时域信号量,该函数将回来二个频限信号量标志符,保存于大局变量sem_id中,然后以往的函数就选拔这一个标记符来访谈功率信号量。

源文件为seml.c,代码如下:

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/sem.h>

//union semun
//{
// int val;
// struct semid_ds *buf;
// unsigned short *arry;
//};

static int sem_id = 0;
static int set_semvalue();
static void del_semvalue();
static int semaphore_p();
static int semaphore_v();

int main(int argc, char *argv[])
{
 char message = 'X';
 int i = 0;

 // 创建信号量
 sem_id = semget((key_t) 1234, 1, 0666 | IPC_CREAT);

 if (argc > 1)
 {
  // 程序第一次被调用,初始化信号量
  if (!set_semvalue())
  {
   fprintf(stderr, "Failed to initialize semaphoren");
   exit(EXIT_FAILURE);
  }

  // 设置要输出到屏幕中的信息,即其参数的第一个字符
  message = argv[1][0];
  sleep(2);
 }

 for (i = 0; i < 10;   i)
 {
  // 进入临界区
  if (!semaphore_p())
  {
   exit(EXIT_FAILURE);
  }

  // 向屏幕中输出数据
  printf("%c", message);

  // 清理缓冲区,然后休眠随机时间
  fflush(stdout);
  sleep(rand() % 3);

  // 离开临界区前再一次向屏幕输出数据
  printf("%c", message);
  fflush(stdout);

  // 离开临界区,休眠随机时间后继续循环
  if (!semaphore_v())
  {
   exit(EXIT_FAILURE);
  }
  sleep(rand() % 2);
 }

 sleep(10);
 printf("n%d - finishedn", getpid());

 if (argc > 1)
 {
  // 如果程序是第一次被调用,则在退出前删除信号量
  sleep(3);
  del_semvalue();
 }
 exit(EXIT_SUCCESS);
}

static int set_semvalue()
{
 // 用于初始化信号量,在使用信号量前必须这样做
 union semun sem_union;

 sem_union.val = 1;
 if (semctl(sem_id, 0, SETVAL, sem_union) == -1)
 {
  return 0;
 }
 return 1;
}

static void del_semvalue()
{
 // 删除信号量
 union semun sem_union;

 if (semctl(sem_id, 0, IPC_RMID, sem_union) == -1)
 {
  fprintf(stderr, "Failed to delete semaphoren");
 }
}

static int semaphore_p()
{
 // 对信号量做减1操作,即等待P(sv)
 struct sembuf sem_b;
 sem_b.sem_num = 0;
 sem_b.sem_op = -1;//P()
 sem_b.sem_flg = SEM_UNDO;
 if (semop(sem_id, &sem_b, 1) == -1)
 {
  fprintf(stderr, "semaphore_p failedn");
  return 0;
 }

 return 1;
}

static int semaphore_v()
{
 // 这是一个释放操作,它使信号量变为可用,即发送信号V(sv)
 struct sembuf sem_b;
 sem_b.sem_num = 0;
 sem_b.sem_op = 1; // V()
 sem_b.sem_flg = SEM_UNDO;
 if (semop(sem_id, &sem_b, 1) == -1)
 {
  fprintf(stderr, "semaphore_v failedn");
  return 0;
 }

 return 1;
}

运作结果如下:

图片 1

注:这么些程序的临界区为main函数for循环不的semaphore_p()和semaphore_v()函数中间的代码。

事例深入分析:

再者运行贰个主次的多个实例,注意第三遍运转时,要丰盛二个字符作为参数,比方本例中的字符‘O’,它用来区分是或不是为率先次调用,同不常候那个字符输出到显示器中。因为种种程序都在其步入临界区后和间隔临界区前打字与印刷一个字符,所以每一种字符都应有成对现身,正如你看看的上海体育场所的出口那样。在main函数中循环中我们得以看到,每便经过要访谈stdout(标准输出卡塔 尔(英语:State of Qatar),即要输出字符时,每回都要检查信号量是不是可用(即stdout有未有正在被别的进度使用卡塔 尔(英语:State of Qatar)。所以,当三个进程A在调用函数semaphore_p()步向了临界区,输出字符后,调用sleep()时,另贰个进度B大概想访谈stdout,不过非确定性信号量的P央求操作失利,只好挂起和煦的实施,当进度A调用函数semaphore_v()离开了临界区,进程B顿时被还原施行。然后进度A和经过B就那样间接循环了13回。

五、对比例子——进程间的财富竞争

看了上边的例子,你或者还不是很领会,但是没什么,上边小编就以另三个例子来证澳优下,它完结的法力与前面包车型地铁事例同样,运营方式也同等,都是四个相符的长河,同一时候向stdout中输出字符,只是未有运用时限信号量,多个进度在互相角逐stdout。它的代码非常轻巧,文件名称叫normalprint.c,代码如下:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
 char message = 'X';
 int i = 0;
 if (argc > 1)
 {
  message = argv[1][0];
 }

 for (i = 0; i < 10;   i)
 {
  printf("%c", message);
  fflush(stdout);
  sleep(rand() % 3);
  printf("%c", message);
  fflush(stdout);
  sleep(rand() % 2);
 }
 sleep(10);
 printf("n%d - finishedn", getpid());

 exit(EXIT_SUCCESS);
}

运作结果如下:

图片 2

事例解析:

从地点的输出结果,大家得以观察字符‘X’和‘O’并不像后边的例证这样,总是成对现身,因为当第多个经过A输出了字符后,调用sleep休眠时,另二个过程B马上输出并休眠,而经过A醒来时,再继续实践输出,同样的进度B也是那样。所以输出的字符正是不成对的面世。那四个进度在竞争stdout那意气风发意气风发并的财富。通过七个例证的相持统生龙活虎,作者想非能量信号量的意义和动用相应相比清楚了。

六、随机信号量的下结论

非非确定性信号量是三个例外的变量,程序对其访谈都以原子操作,且只同意对它实行等待(即P(非时限信号变量))和发送(即V(连续信号变量))音信操作。大家日常经过时限信号来缓和多个进度对相符财富的拜谒角逐的标题,使在任有的时候刻只好有叁个实行线程访谈代码的靠拢区域,也得以说它是谐和进程间的对同一财富的访谈权,也便是用于协作进程的。

 


 

注意:

事例中的进度分为三种,大器晚成种是运作时包括命令行参数的进程,后生可畏种是运作时不分包参数的经过。后面一个担当信号量的创办、设置初值并销毁,而后尘凡接拿走并接收前面一个创建并安装好的频限信号量。

 

 

参考:

《Linux 高品质服务器编程》

本文由67677新澳门手机版发布于67677新澳门手机版,转载请注明出处:Linux进度间通讯

关键词: