精华内容
下载资源
问答
  • 进程间通信IPC-信号量

    2016-06-29 10:36:00
    semget函数创建一个新的信号量或是获得一个已存在的信号量键值。 1 int semget(key_t key, int num_sems, int sem_flags); 第一个参数key是一个用来允许不相关的进程访问相同信号量的整数值。所有的信号量是为...

    semget 

    semget函数创建一个新的信号量或是获得一个已存在的信号量键值。

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

    第一个参数key是一个用来允许不相关的进程访问相同信号量的整数值。所有的信号量是为不同的程序通过提供一个key来间接访问的,对于每一个信号量系统 生成一个信号量标识符。信号量键值只可以由semget获得,所有其他的信号量函数所用的信号量标识符都是由semget所返回的。还有一个特殊的信号量key值,IPC_PRIVATE(通常为0),其作用是创建一个只有创建进程可以访问的信号量。这通常并没有有用的目的,而幸运的是,因为在某些Linux系统上,手册页将IPC_PRIVATE并没有阻止其他的进程访问信号量作为一个bug列出。num_sems参数是所需要的信号量数目。这个值通常总是1。sem_flags参数是一个标记集合,与open函数的标记十分类似。低九位是信号的权限,其作用与文件权限类似。另外,这些标记可以与 IPC_CREAT进行或操作来创建新的信号量。设置IPC_CREAT标记并且指定一个已经存在的信号量键值并不是一个错误。如果不需 要,IPC_CREAT标记只是被简单的忽略。我们可以使用IPC_CREAT与IPC_EXCL的组合来保证我们可以获得一个新的,唯一的信号量。如果这个信号量已经存在,则会返回一个错误。如果成功,semget函数会返回一个正数;这是用于其他信号量函数的标识符。如果失败,则会返回-1。

    semop 

    函数semop用来改变信号量的值: 

    第一个参数,sem_id,是由semget函数所返回的信号量标识符。第二个参数,sem_ops,是一个指向结构数组的指针,其中的每一个结构至少包含下列成员:

    1 struct sembuf {
    2     short sem_num;
    3     short sem_op;
    4     short sem_flg;
    5 }
    第一个成员,sem_num,是信号量数目,通常为0,除非我们正在使用一个信号量数组。sem_op成员是信号量的变化量值。(我们可以以任何量改变信 号量值,而不只是1)通常情况下中使用两个值,-1是我们的P操作,用来等待一个信号量变得可用,而+1是我们的V操作,用来通知一个信号量可用。最后一个成员,sem_flg,通常设置为SEM_UNDO。这会使得操作系统跟踪当前进程对信号量所做的改变,而且如果进程终止而没有释放这个信号量, 如果信号量为这个进程所占有,这个标记可以使得操作系统自动释放这个信号量。将sem_flg设置为SEM_UNDO是一个好习惯,除非我们需要不同的行 为。如果我们确实变我们需要一个不同的值而不是SEM_UNDO,一致性是十分重要的,否则我们就会变得十分迷惑,当我们的进程退出时,内核是否会尝试清 理我们的信号量。semop的所用动作会同时作用,从而避免多个信号量的使用所引起的竞争条件。我们可以在手册页中了解关于semop处理更为详细的信息。

    semctl 。semctl函数允许信号量信息的直接控制:

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

      

    第一个参数,sem_id,是由semget所获得的信号量标识符。sem_num参数是信号量数目。当我们使用信号量数组时会用到这个参数。通常,如果 这是第一个且是唯一的一个信号量,这个值为0。command参数是要执行的动作,而如果提供了额外的参数,则是union semun,根据X/OPEN规范,这个参数至少包括下列参数:

    1 union semun {
    2     int val;
    3     struct semid_ds *buf;
    4     unsigned short *array;
    5     struct seminfo* __buf;
    6 }

    许多版本的Linux在头文件(通常为sem.h)中定义了semun联合,尽管X/Open确认说我们必须定义我们自己的联合。如果我们发现我们确实需 要定义我们自己的联合,我们可以查看semctl手册页了解定义。如果有这样的情况,建议使用手册页中提供的定义,尽管这个定义与上面的有区别。有多个不同的command值可以用于semctl。在这里我们描述两个会经常用到的值。要了解semctl功能的详细信息,我们应该查看手册页。这两个通常的command值为:SETVAL:用于初始化信号量为一个已知的值。所需要的值作为联合semun的val成员来传递。在信号量第一次使用之前需要设置信号量。IPC_RMID:当信号量不再需要时用于删除一个信号量标识。semctl函数依据command参数会返回不同的值。对于SETVAL与IPC_RMID,如果成功则会返回0,否则会返回-1。

    使用信号量 

     1 #include <sys/sem.h>
     2 #include <stdio.h>
     3 #include <stdlib.h>
     4 #include <unistd.h>
     5 #include <sys/wait.h>
     6 
     7 union semun
     8 {
     9      int val;
    10      struct semid_ds* buf;
    11      unsigned short int* array;
    12      struct seminfo* __buf;
    13 };
    14 
    15 void pv( int sem_id, int op )
    16 {
    17     struct sembuf sem_b;
    18     sem_b.sem_num = 0;
    19     sem_b.sem_op = op;
    20     sem_b.sem_flg = SEM_UNDO;
    21     semop( sem_id, &sem_b, 1 );
    22 }
    23 
    24 int main( int argc, char* argv[] )
    25 {
    26     int sem_id = semget( IPC_PRIVATE, 1, 0666 );
    27 
    28     union semun sem_un;
    29     sem_un.val = 1;
    30     semctl( sem_id, 0, SETVAL, sem_un );
    31 
    32     pid_t id = fork();
    33     if( id < 0 )
    34     {
    35         return 1;
    36     }
    37     else if( id == 0 )
    38     {
    39         printf( "child try to get binary sem\n" );
    40         pv( sem_id, -1 );
    41         printf( "child get the sem and would release it after 5 seconds\n" );
    42         sleep( 5 );
    43         pv( sem_id, 1 );
    44         exit( 0 );
    45     }
    46     else
    47     {
    48         printf( "parent try to get binary sem\n" );
    49         pv( sem_id, -1 );
    50         printf( "parent get the sem and would release it after 5 seconds\n" );
    51         sleep( 5 );
    52         pv( sem_id, 1 );
    53     }
    54 
    55     waitpid( id, NULL, 0 );
    56     semctl( sem_id, 0, IPC_RMID, sem_un );
    57     return 0;
    58 }

     

    转载于:https://www.cnblogs.com/borey/p/5625977.html

    展开全文
  • 信号量相关函数整理

    2016-10-25 19:34:31
    信号量相关函数整理   1.semget 作用:创建信号量 原型:int semget(key_t...参数:key 信号量键值  nsems 需要创建的信号量数目,通常取一个  semflg 同open一样的权限 返回值:成功信号量标识符  出错 -1

    信号量相关函数整理

     

    1.semget

    作用:创建信号量

    原型:int semget(key_t key, int nsems, int semflg)

    参数:key 信号量键值

               nsems 需要创建的信号量数目,通常取一个

               semflg 同open一样的权限

    返回值:成功信号量标识符

                       出错 -1

    头文件:sys/types.h

                       sys/ipc.h

                       sys/sem.h

     

    2.semctl

    作用:信号量控制

    原型:int semctl(int semid, int semnum, int cmd, union semnn arg)

    参数:semnum 通常为0,表示第一个信号量

               cmd IPC_STAT

                         IPC_SETVAL

                         IPC_GETCAL

               arg union semnn

    返回值:cmd->不同的命令返回值不同

                       IPC_STAT,IPC_SETVAL, IPC_RMID返回值为0

                       IPC_GETVAL返回信号量的值

                 出错 -1

     

    3.semop

    作用:执行PV操作

    原型:int semop(int semid, struct sembuf *sops, size_t nsops)

    参数:semid 信号集的识别码,可以通过semget获取

               semop -1:P操作,+1:V操作

               nsops 信号操作结构的数量,恒大于或等于1

    返回值:成功 0

                       失败 -1

     

    展开全文
  • 内存映射,键值含义,共享内存,消息队列,信号量 1.内存映射: 概念: 系统在调用进程的虚拟地址空间创建一个新内存映射 文件映射: 将文件映射到进程空间得到一个可操作的地址, 对地址操作就是对文件直接读写 ...

    内存映射,键值含义,共享内存,消息队列,信号量

    1.内存映射:

    概念:
    系统在调用进程的虚拟地址空间创建一个新内存映射

    文件映射:
    将文件映射到进程空间得到一个可操作的地址,
    对地址操作就是对文件直接读写

    属性:

    私有映射
    MAP_PRIVATE
    在映射内容上发生的变化对其他进程不可见
    对文件映射来说不会影响底层文件
    共享映射
    MAP_SHARED
    在映射内容上发生的变化对其他进程可见
    对文件映射来说会影响底层文件

    映射mmap:

    功能
    内存映射函数mmap, 负责把文件内容映射到进程的虚拟内存空间, 通过对这段内存的读取和修改,来实现对文件的读取和修改,而不需要再调用read,write等操作。
    原型
    void *mmap(void *start, size_t length, int prot, int flags,int fd, off_t offset);
    参数
    start:指定映射到进程空间的地址,指定为NULL表示系统自动分配
    length:指定映射的文件长度,单位是 以字节为单位,不足一内存页按一内存页处理
    prot:期待获取的操作,需要两个权限的可以用或|
    PROT_EXEC映射区可被执行
    PROT_READ映射区可被读取
    PROT_WRITE映射区可被写入
    PROT_NONE映射区不可访问
    flags标志
    MAP_SHARED对此区域所做的修改内容将写入文件内;允许其他映射该文件的进程共享
    MAP_PRIVATE:对此区域所做的修改不会更改原来的文件内容,对映射区的写入操作会产生一个映射区的复制
    fd文件描述符要映射的文件
    offset:文件起始偏移量
    设置为0
    返回值
    成功返回映射成功后的地址
    失败返回-1
    注意
    权限

    解除munmap:

    原型:
    int munmap(void *start, size_t length);
    解除映射操作

    内存操作函数:

    操作一个内存块
    memcpy
    内存拷贝函数
    void *memcpy(void *dest, const void *src, size_t n);
    目标地址
    源地址
    复制内容大小
    返回一个指向dest的指针
    memcpy(p,“hello”,6);
    write();
    memset
    对一个内存块进行整体的赋值常用清空内存块
    memset(char *p,int num,int size);
    内存中某个首地址
    需要赋的值
    需要赋的字节数大小 (memset(a,0,sizeof(a))):清零
    memset(p,0,10);

    注意:
    只能对已有的文件内容做修改:

    代码演示:

    #include <stdio.h>
    #include <unistd.h>
    #include <sys/mman.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <string.h>
    int main()
    {
     int fd = open("./demo1.c",O_RDWR);//不能打开时新建,因为新文件大小为0
     //int fd = open("./demo1.c",O_RDWR|O_CREAT,0777);
     int len= lseek(fd,0,SEEK_END);
     char *p=mmap(NULL,len,PROT_WRITE,MAP_SHARED,fd,0);
     //char *p=mmap(NULL,len,PROT_WRITE,MAP_PRIVATE,fd,0);//映射大小不能为0
     if(p==(char *)-1)
     {
      perror("mmap");
      return 0;
     }
     memcpy(p,"hell0 world",12);//覆盖前12字节
     //memset(p,'1',20);//写入时:是将整形转化为 char
     //strcpy(p,"hello");
     //printf("%s\n",p);//%s遇/0结束
     //printf("%s\n",p+12);
     return 0;
    }

    说明:

    char *p=mmap(NULL,len,PROT_WRITE,MAP_SHARED,fd,0);
     char *p=mmap(NULL,len,PROT_WRITE,MAP_PRIVATE,fd,0);//映射大小不能为0
    

    1.共享映射可以改变,私有映射无法改变(但能够打印出来),并且映射的内容大小不能为0;

    2.必须对已有的文件进行映射,且已有文件大小>0,映射内容的大小可以超过文件的大小,不能打开时候新建,因为新建文件大小为0,会映射失败。

    int fd = open("./demo1.c",O_RDWR|O_CREAT,0777);
    //错误

    3.memset:写入时:将整型转化为 char(0不需要)

    memset(p,'1',20);

    2.键值含义:

    定义:
    用于标识共享内存、消息队列以及信号量集
    保证进程打开的共享内存、消息队列、信号量集是同一个

    获取键值:

    ftok
    功能
    获取键值
    原型
    key_t ftok(const char *pathname, int proj_id);
    所属头文件
    # include <sys/types.h>
    # include <sys/ipc.h>
    参数
    pathname就时你指定的文件名(该文件必须是存在而且可以访问的)
    proj_id是子序号,虽然为int,但是只有8个比特被使用(0-255)
    返回值
    当成功执行的时候,一个key_t值将会被返回,否则 -1 被返回

    3.共享内存:

    指令:

     ipcs -m   //看Shared Memory 共享内存
     ipcs -s   //看Semaphore Arrays 信号量
     ipcs -q   //看Message Queues 消息队列

    在这里插入图片描述

    定义:
    在操作系统内核开辟一个空间,每一个进程都可以将这个空间映射到自己的进程空间里面,多个进程可以共享这块内存,对他的操作都可以立即实现。

    过程:

    创建共享内存
    进程1映射内存进行读写
    进程2映射共享内存进行读写
    进程1、进程2 解除映射
    删除共享内存

    相关API:

    创建:

    功能
    用来获得共享内存区域的ID,如果不存在指定的共享区域就创建相应的区域
    原型
    int shmget(key_t key, size_t size, int shmflg);
    头文件
    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>
    参数
    key:键值
    IPC_PRIVATE//键值为0 表示创建的共享内存只能父子间用
    ftok()//任意进程都可以用
    size:大小
    shmflg:标志(IPC_CREAT没有就创建)同 open 函数的权限位,也可以用八进制表示法
    返回值
    成功返回内存段标识符,失败-1

    映射:

    功能
    把共享内存区域映射到调用进程的地址空间中去
    原型
    void *shmat(int shmid, const void *shmaddr, int shmflg);
    头文件
    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>
    参数
    shmid要映射的共享内存区标识符
    shmaddr:将共享内存映射到指定位置(若为 0 则表示把该段共享内存映射到调用进程的地址空间
    shmflg:默认 0:共享内存可读写
    SHM_RDONLY:共享内存只读
    返回值
    成功:被映射的段地址,失败返回-1

    解除:

    功能
    调用用来解除进程对共享内存区域的映射
    原型
    int shmdt(const void *shmaddr);
    头文件
    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>
    参数
    被映射的共享内存段地址
    返回值
    成功返回0失败返回-1

    设置:
    原型

    int shmctl(int shmid, int cmd, struct shmid_ds *buf);
    参数
    shmid
    shmget的返回值
    cmd
    选择的操作
    IPC_STAT:获取共享内存属性
    IPC_SET:修改共享内存
    IPC_RMID:删除共享内存,此时第三个参数为NULL
    buf

    //获取共享内存属性
    structshmid_ds*buf=malloc(sizeof(structshmid_ds));
    structshmid_dsbuf;
    shmctl(shm,IPC_STAT,&buf);

    演示案例:创建共享内存,供父子之间进行使用:

    演示代码:

    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>
    #include <string.h>
    #include <unistd.h>
    #include <sys/wait.h>
    int main()
    {
     char *p =NULL;
     char buf[100] = "IPC shmred memory";
     //1.获取共享内存标识  或者 创建
     int shm=shmget(IPC_PRIVATE,200,IPC_CREAT);//IPC_PRIVATE//键值为0 表示创建的共享内存只能父子间用
     printf("shm=%d\n",shm);
     if(shm==-1)
     {
      perror("shmget");
      return -1;
     }
     pid_t pid = fork();
     if(pid==0)
     {    //将共享内存映射到进程里面
      p=shmat(shm,NULL,0);//0--可以对共享内存可读可写
      memset(p,0,200);//清理空间
      memcpy(p,buf,strlen(buf));
      //getchar();//等待输入一个字符
      //shmdt(p);//解除共享内存
     }
     else
     {
     //getchar();//等待输入一个字符
      //shmdt(p);//解除共享内存
      p = shmat(shm,NULL,0);//0--可以对共享内存可读可写
      wait(NULL);
      printf("father: %s\n",p);
    
    //sleep(5);
    //shmctl(shm,IPC_RMID,0);//删除共享内存
    
     }
     return 0;
    }

    在这里插入图片描述
    注意
    需要在管理员权限下运行程序。

    查看shmdt解除映射的效果和shmctl删除共享内存的效果,可以通过 :

    ipcs -m

    查看。

    案例演示2:
    非亲缘关系之间的共享内存进行通信:

    演示代码:
    写操作:

    #include <sys/ipc.h>
    #include <sys/shm.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <string.h>
    //int shmget(key_t key, size_t size, int shmflg);
    int main()
    {
    int shmid;
    char *shmaddr;
    key_t key;
    key=ftok(".",1);//获取键值--内核位置
    shmid=shmget(key,1024*4,IPC_CREAT|0666);//共响内存以兆为单位,关键字:创造
    if(shmid==-1)
    {
    printf("创建共响内存失败\n");
    exit(-1);//通常设定,异常返回-1,正常返回0
    }
    // void *shmat(int shmid, const void *shmaddr, int shmflg);
    shmaddr=shmat(shmid,0,0);//连接共响内存,shmflg:0:代表映射进来的共响内存可读可写,,完成共项内存的映射
    printf("连接成功\n");
    strcpy(shmaddr,"liujinhui");//写入内容
    sleep(5);//写完后睡5s,让别的程序读走
    //int shmdt(const void *shmaddr);
    shmdt(shmaddr);//断开连接
    //int shmctl(int shmid, int cmd, struct shmid_ds *buf);
    shmctl(shmid,IPC_RMID,0);//关闭共响内存/删除
    printf("退出\n");
    return 0;
    }
    

    读操作:

    #include <sys/ipc.h>
    #include <sys/shm.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <string.h>
    //int shmget(key_t key, size_t size, int shmflg);
    int main()
    {
    int shmid;
    char *shmaddr;
    key_t key;
    key=ftok(".",1);//获取键值--内核位置
    shmid=shmget(key,1024*4,0);//共响内存以兆为单位,关键字:不创造
    if(shmid==-1)
    {
    printf("创建共响内存失败\n");
    exit(-1);//通常设定,异常返回-1,正常返回0
    }
    // void *shmat(int shmid, const void *shmaddr, int shmflg);
    shmaddr=shmat(shmid,0,0);//连接共响内存,shmflg:0:代表映射进来的共响内存可读可写,,完成共项内存的映射
    printf("连接成功\n");
    printf("data:%s\n",shmaddr);//读出内容 
    //int shmdt(const void *shmaddr);
    shmdt(shmaddr);//断开连接
    printf("退出\n");
    return 0;
    }
    

    运行结果:
    在这里插入图片描述

    注意:在./write之后5s内操作./read

    4.消息队列:

    4.1:消息队列的概念:

    消息队列就是一个消息的队列。可以把消息看作一个记录,具有特定的格式以及特定的优先级。对消息队列有写权限的进程可以向其中按照一定的规则添加新消息;对消息队列有读权限的进程则可以
    从消息队列中读走消息。

    4.2:消息队列使用流程:

    获取键值
    创建或者访问一个消息队列
    向队列读/写消息
    销毁队列

    4.3:消息队列相关API:

    创建或打开:
    功能:
    建新消息队列或取得已存在消息队列
    原型:

     int msgget(key_t key, int msgflg);

    所属头文件:
    #include <sys / types.h>
    #include <sys / ipc.h>
    #include <sys / msg.h>
    参数:

    key:可以认为是一个端口号,也可以由函数ftok生成。
    IPC_PRIVATE:只能父子进程使用;
    非0值–自己指定或者ftok获取—任意进程使用;
    msgflg:
    IPC_CREAT值,若没有该队列,则创建一个并返回新标识符;若已存在,则返回原标识符。
    IPC_EXCL值,若没有该队列,则返回-1;若已存在,则返回0。
    IPC_NOWAIT读写消息队列要求不满足不会阻塞。

    返回值:
    成功执行时,返回消息队列标识值。失败返回-1,
    标识供发送,接收,删除使用

    添加消息队列:
    功能:
    把消息添加到已打开的消息队列末尾
    原型:

     int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

    所属头文件
    #include <sys / types.h>
    #include <sys / ipc.h>
    #include <sys / msg.h>
    参数:

    msgid: 指明消息队列的 ID, 通常是 msgget 函数成功的返回值
    msgp:发送数据缓冲区首地址
    msgp:指向消息结构的指针。该消息结构 msgbuf 为:
    struct msgbuf{
    long mtype;//消息类型----必须是long类型
    char mtext[1];//消息正文
    }—需要自己定义
    msgsz:数据大小,每个消息体最大不要超过 4K
    msgflg:一般赋0,阻塞方式
    IPC_NOWAIT 若消息并没有立即发送而调用进程会立即返回

    返回值:
    成功则返回0, 出错则返回-1

    读取消息:
    功能:
    把消息从消息队列中取走,与 FIFO 不同的是,这里可以指定取走某一条消息
    原型:

    ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);

    所属头文件:
    #include <sys / types.h>
    #include <sys / ipc.h>
    #include <sys / msg.h>
    参数:

    msqid:消息队列的队列 ID
    msgp:消息缓冲区
    size:消息的字节数,不要以 null 结尾
    msgtyp:消息类型 =0 忽略类型 >0 只接收指定类型的数据
    <0 只接受小于等于其绝对值的数据
    接收的类型为0
    默认接收当前消息队列第一条数据
    接收类型>0
    接收指定类型的第一条,如果没有,阻塞(需要参考flag)
    接收类型小于0
    接收小于等于该类型绝对值的最小类型的第一条消息
    MSG_NOERROR:若返回的消息比 size 字节多,则消息就会截短到size 字节,且不通知消息发送进程
    IPC_NOWAIT :若消息并没有立即接收而调用进程会立即返回
    函数传入值.
    0:msgrcv调用阻塞直到条件满足为止

    返回值:
    接收成功返回0,失败返回-1

    控制消息队列:
    功能:
    控制消息队列使用
    原型:

    int msgctl(int msqid, int cmd, struct msqid_ds *buf);

    所属头文件:
    #include <sys / types.h>
    #include <sys / ipc.h>
    #include <sys / msg.h>
    参数

    msqid:消息队列的队列 ID
    cmd:
    IPC_STAT:读取消息队列的数据结构 msqid_ds,并将其存储在buf 指定的地址中
    IPC_SET:设置消息队列的数据结构 msqid_ds 中的 ipc_perm 元素的值。这个值取自 buf 参数
    IPC_RMID:从系统内核中移走消息队列
    Buf:消息队列缓冲区

    返回值:
    接收成功返回0,失败返回-1

    案例演示
    建立消息队列,一段负责写入,一段负责读取。

    write.c

    #include <stdio.h>
    #include <sys/ipc.h>
    #include <sys/msg.h>
    #include <unistd.h>
    #include <string.h>
    #include <sys/types.h>
    struct Msg
    {
     long mtype;
     char mtext[100];
    };
    int main()
    {
     struct Msg w_buf;
     //创建/获取消息队列标识符
     int msg = msgget(12,IPC_CREAT);
     printf("msg = %d\n",msg);
     while(1)
     {
      memset(&w_buf,0,sizeof(w_buf));
      printf("请输入消息类型:");
      scanf("%ld",&w_buf.mtype);
      printf("请输入消息内容:");
      scanf("%s",w_buf.mtext);
      msgsnd(msg,&w_buf,sizeof(w_buf),0);
      perror("msgsnd");
     }
    // msgctl(msg,IPC_RMID,NULL);//从内核中删除消息队列
     return 0;
    }

    read.c

    #include <stdio.h>
    #include <sys/ipc.h>
    #include <sys/msg.h>
    #include <unistd.h>
    #include <string.h>
    #include <sys/types.h>
    struct Msg
    {
     long mtype;
     char mtext[100];//非循环发送消息时,读空间应大于写,不然会段错误
    };
    int main()
    {
     struct Msg r_buf;
     long type;
     int ret;
     //创建/获取消息队列标识符
     int msg = msgget(12,IPC_CREAT);
     printf("msg = %d\n",msg);
     while(1)
     {
      memset(&r_buf,0,sizeof(r_buf));
      printf("请输入读取消息的类型:");
      scanf("%ld",&r_buf.mtype); 
      ret = msgrcv(msg,&r_buf,sizeof(r_buf),r_buf.mtype,0);
      perror("msgrcv");
      printf("ret = %d\n",ret);
      printf("read: %ld\t%s\n",r_buf.mtype,r_buf.mtext);
     }
     return 0;
    }

    运行结果:
    。。。

    5.信号量:

    5.1:信号量的定义:

    信号量是多进程/多线程同步的一种方式,可以实现对共享资源的保护--------资源允许操作的最大数目

    5.2:信号量工作原理:

    对共享资源访问保护:

    1) 初始化信号量值为 1
    2) 获得信号量 — 》 把信号值-1 —》 变成 0
    3) 操作要保护的代码
    4) 释放信号量 —》 把信号值+1

    在这里插入图片描述
    原理:

    访问临界资源的代码叫做临界区,临界区本身也会称为临界资源.
    硬件资源(处理器、内存、存储器及其它外围设备等)和软件资源(共享代码段、共享结构和变量等)

    P(sv):如果sv的值大于零,就给它减1;如果它的值为零,就挂起该进程的执行
    V(sv):如果有其他进程因等待sv而被挂起,就让它恢复运行,如果没有进程因等待sv而挂起,就给它加1

    5.3:信号量使用流程:

    1) 创建信号集。
    信号集: 一个信号量变量是一个信号量,多个信号量就是组成一个集合,类似数组。
    2)初始化信号集中的每个信号值。
    3)需要保护的临界代码前进行 P 操作。
    对信号值的获得操作 ,称为 P 操作
    4)执行完成临界代码后进行 V 操作。
    释放信号称为== V 操作==
    5) 不需要时候删除信号集

    5.4:信号量相关API:

    创建/访问:
    原型:

     int semget(key_t key, int nsems, int semflg);

    参数:
    key:键值

    IPC_PRIVATE//键值为0 表示创建一个只有创建者进程才可以访问的信号量
    ftok()//可以被多个进程共享的信号量
    nsems
    需要使用的信号量数目
    semflg
    IPC_CREAT

    返回值:
    失败: -1;成功:正数,表示信号集的 id

    设置初始值:
    原型:

     int semctl(int semid, int semnum, int cmd, ...);

    参数:

    semid
    semget返回的信号量标识符
    semnum
    要进行的操作的集合中信号量的编号,一般取0
    cmd
    删除:IPC_RMID
    设置一个:SETVAL
    获取一个:GETVAL
    获取全部:GETALL
    设置全部:SETALL
    设置属性:IPC_SET
    获取属性:IPC_STAT

    消耗/还原 信号量semop:
    原型:

    int semop(int semid, struct sembuf *sops, unsigned nsops);

    功能:
    修改信号集合中的信号量值,实现 PV 操作
    参数:

    semid:semget返回值
    sops:对信号量的操作
    封装了一个结构体里面有
    unsigned short sem_num; /* 集合中的信号量编号,实际就是数组下标,从 0 开始 /
    short sem_op; /
    要调整的信号值,把原来的信号值进行+/- sem_op 操作,一般是-1 或 1 /
    short sem_flg; /
    操作标志, IPC_NOWAIT 表示当不能获得信号量时不阻塞,返回错误;
    SEM_UNDO 表示内核自动跟踪进程是否异常终止,如果持有信号量的进程异常中止,内核会还原信号量,
    避免其他进程得不到信号永久等待这种情况。一般设置为0。 */
    nsops:表示要操作的信号量数量

    案例演示:

    创建2个进程,进行pv操作:

    展开全文
  • 不同进程通过使用同一个信号量键值来获得同一个信号量。 ② 初始化信号量,此时使用 semctl() 函数的SETVAL操作。当使用二维信号量时,通常将信号量初始化为1。 ③ 进行信号量的PV操作,此时,调用 semop()函数。这...

    在Linux系统中,使用信号量通常分为以下4个步骤:

    ① 创建信号量或获得在系统中已存在的信号量,此时需要调用 semget() 函数。不同进程通过使用同一个信号量键值来获得同一个信号量。

    ② 初始化信号量,此时使用 semctl() 函数的SETVAL操作。当使用二维信号量时,通常将信号量初始化为1。

    ③ 进行信号量的PV操作,此时,调用 semop()函数。这一步是实现进程间的同步和互斥的核心工作部分。

    ④ 如果不需要信号量,则从系统中删除它,此时使用semctl()函数的 IPC_RMID操作。需要注意的是,在程序中不应该出现对已经被删除的信号量的操作。

    在这里插入图片描述在这里插入图片描述在这里插入图片描述
    参考链接

    展开全文
  • Linux内核IPC机制之信号量

    千次阅读 2014-11-25 22:06:36
    当某个进程使用到信号量的时候,它会进行信号量的创建,创建时传入一个键值,同时返回信号量的描述符,该创建进程的命名空间中保存了与该信号量键值对应的id,该id对应sem_array结构,id和该结构的对应是通过idr来...
  • * sem_id : 信号量键值, 一个唯一的非零整数, 不同的进程可以通过它访问同一个信号量。 * num_sems : 信号量数目, 它几乎总是取值为1. * sem_flags: 它低端的9个比特是该信号量的权限,其作用类.
  • 标签:信号量(3)Linux(1561)8.4.1 信号量概述在多任务操作系统环境下,多个进程会同时运行,并且一些进程之间可能存在一定的关联。多个进程可能为了完成同一个任务会相互协作,这样形成进程之间的同步关系。而且在...
  • 信号量

    万次阅读 多人点赞 2017-03-10 20:44:41
    一、首先:我们要知道信号量是什么?  信号量的本质是数据操作锁,它本身不具有数据交换的功能,而是通过控制其他的通信资源(文件,外部设备)来实现进程间通信,它本身只是一种外部资源的标识。信号量在此过程中...
  • Linux 信号量使用

    2016-09-02 22:29:27
    功能:创建一个新的信号量或获取一个已经存在的信号量键值。 返回值:成功返回信号量的标识码ID。失败返回-1; 参数: _key 为整型值,用户可以自己设定。有两种情况: 1. 键值是IPC_P
  • 在System V中,我们经常用用key_t的值来创建或者打开信号量,共享内存和消息队列。这个在IPC的环境中十分的重要,比如说,服务器创建了一个消息队列,等待 客户机发送请求。那么如何创建或者打开已有的消息队列呢?...
  • Linux进程IPC浅析[进程间通信SystemV进程的信号量信号量集](对共享资源主要实现互斥同步效果) 1. 进程信号量概念 2. 进程信号量集进程信号量的概念本质上就是共享资源的数据(非负的计数器),用来控制对共享资源...
  • 【Linux系统编程】System V信号量

    千次阅读 2019-11-08 11:49:14
    信号量操作函数3.1 创建信号量数组3.2 信号量控制函数3.3 信号量操作函数04. 程序示例05. 附录 01. 信号量概述 信号量广泛用于进程或线程间的同步和互斥,信号量本质上是一个非负的整数计数器,它被用来控制对公共...
  • 【Linux】Linux的信号量

    万次阅读 2018-08-18 22:33:08
    所谓信号量集,就是由多个信号量组成的一个数组。作为一个整体,信号量集中的所有信号量使用同一个等待队列。Linux的信号量集为进程请求多个资源创造了条件。Linux规定,当进程的一个操作需要多个共享资源时,如果只...
  • 信号量讲解

    2018-04-13 12:17:57
    信号量一、概述1. 工作原理: 当一个进程要求使用共享内存中的资源时,系统会首先判断该资源的信号量,即统计可以访问该资源的单元个数。如果系统判断该资源的信号量大于0,进程就可以访问该资源,并且信号量要减...
  • 信号量概述 信号量与已经介绍过的IPC结构不同,它是一个计数器。信号量用于实现进程间的互斥与同步,而不是用于存储进程间通信数据 特点: 信号量用于进程间同步,若要在进程间传递数据需要结合共享内存 信号量基于...
  • 一、 System V信号灯API  System V消息队列API只有三个,使用时需要包括几个头文件: ...参数key是一个键值,由ftok获得,唯一标识一个信号灯集. 参数nsems指定信号灯集包含信号灯的数目; semf
  • 一、信号量(semaphore)  在进程互斥中,信号量主要用来保护临界资源。进程通过信号量来判断 是否能够访问该共享资源。(当然,后面我们还会用来控制进程同步)。 二、信号量类型 1、二值信号...
  • 任务同步简介,事件标志组,信号量同步

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 23,392
精华内容 9,356
关键字:

信号量的键值