您的位置:首页 > 运维架构 > Linux

LINUX_C编程实战—第十章《进程间的通信》-信号量

2017-11-06 18:36 274 查看
好久没更新博客啦,今天工作闲了可以做一个终结啦。

System V信号量的概念:可以理解为一个计数器,主要用于对临界资源的访问,进行PV操作(P操作,获取资源,资源数-1;V操作释放资源,资源数+1);信号量的值大于或等于0时表示可供并发进程使用的资源实体数,小于0表示正在等待使用临界资源的进程数。一般用的最多的为二进制信号量,既值取0,1;

键值:可以理解为IPC的一个中间介值,用来进行通信的,由ftok函数创建;

key_t ftok( const char *pathname, int proj_id); //文件的设备编号和节点

                             函数调用成功返回key_t键值,出错返回-1;其中在unix系统中,proj_id是子序列,为一个8bit的整数,范围为0-255;

     此外要特别注意当pathname指向的文件或目录被删除而且又重新创建时,可以正常创建键值,但键值确和之前的值不一样啦,程序运行不会报错,但无法达到传输通信的作用。确保键值不变,要么保证ftok的文件不被删除,要么不用ftok,指定一个固定的key值

  一、信号量的创建:

                                         #include<sys/sem.h>

int semget( key_t key, int nsems, int semflg);//执行成功返回信号量标识符,失败返回-1;

                                     nsems:信号量集中包含的信号量个数;

     semflg:操作标识,IPC_CREATE | IPC_EXCL(信号集已有则返回错误)

二、信号量的操作(+-1)

int semop( int semid, struct sembuf *sops, size_t nsops);//成功返回0,失败返回-1;

semid;信号集标识符;

struct sembuf {

ushort sem_num;//信号量在信号量集中的索引

        short sem_op;//操作类型,+1(释放资源,资源数加1)  or  -1(使用资源,资源数减少)  

short sem_flg;//操作标志,IPC_NOWAIT  或 0;

}

nsops:将要进行操作的信号量个数,>=1

三、信号集控制: 对信号集中的信号量赋值、取值、删除等;

int semctl( int semid, int semnum,int cmd, union semun);//成功返回0,失败返回-1;

semid:信号量集标识符

semnum:操作信号量在信号量集中的编号,第一个信号量的标号为0;

cmd:取值可为SETVAL、GETVAL、IPC_RMID等;

union semun{

int val;

struct semid_ds *buf;

ushort *array;

struct seminfo *buf;

void *pad;

}

测试代码如下:实现进程间的同步

头文件:sem.h

#ifndef _SEM_H_
#define _SEM_H_

#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/sem.h>
#include<unistd.h>
#include<sys/wait.h>

#define PATHNAME "."
#define NUMBER 1

int creat_sem(int sems);

int init_sem(int semid,int which,int value);

int get_sem();

int p_sem(int semid,int which,int *flag);

int v_sem(int semid,int which);

int destroy(int semid);

#endif


sem.c文件

#include "sem.h"

/* 创建信号量集*/
int creat_sem(int sems)
{
key_t key;
int semid;
/* 利用ftok创建键值*/
key=ftok(PATHNAME,NUMBER);
if(key < 0)
{
perror("ftok error");
exit(1);
}
/* 创建信号量集函数*/
semid=semget(key,sems,IPC_CREAT | 0666);
if(semid < 0)
{
perror("sem_get error");
exit(1);
}

return semid;
}
int get_sem()
{
/* 利用IPC_CREAT打开已创建的信号量集*/
return creat_sem(2);
}
/* 不懂为啥还要重复定义共同体,不定义就找不到定义的参数argc*/
union semun
{
int val; // value for SETVAL
struct semid_ds *buf; // buffer for IPC_STAT & IPC_SET
unsigned short *array; // buffer for GETALL & SELALL
struct seminfo * __buf; // buffer for IPC_INFO
};

/* 初始化信号集*/
int init_sem(int semid,int which,int value)
{
union semun argc;
int ret;
argc.val = value;
/* semctl函数用于初始化编号为which的信号集;亦可用于删除*/
ret = semctl(semid,which,SETVAL,argc);
if(ret < 0)
{
perror("semctl error");
exit(1);
}

return 0;
}

/* P操作获取资源,资源数-1 */
int p_sem(int semid,int which,int *flag)
{
struct sembuf sbuf={which,-1,0};
int ret;

ret = semop(semid,&sbuf,1);
if(ret < 0)
{
perror("p_sem error");
/* 出错标志位*/
*flag = 1;
exit(0);
}
return 0;

}

/* V操作释放资源,资源数+1 */
int v_sem(int semid,int which)
{
struct sembuf sbuf={which,1,0};
int ret;

ret = semop(semid,&sbuf,1);
if(ret < 0)
{
perror("v_sem error");
exit(0);
}
return 0;
}

/* 清空信号集*/
int destroy(int semid)
{
int ret;
/* 使用参数IPC_RMID删除信号集*/
ret = semctl(semid,0,IPC_RMID,0);
if(ret < 0)
{
perror("semctl error");
exit(1);
}
return 0;
}
主函数:

#include "sem.h"

int main(int argc,char **argv)
{
pid_t pid;
int semid,sem_id;

/* 创建键值 */
semid = creat_sem(10);

init_sem(semid,0,1);
pid = fork();

if(pid < 0)
{
perror("fork error");
exit(0);
}
else if(pid == 0)
{
/* 获得键值*/
sem_id = get_sem();
//printf("sem_id=%d\n",sem_id);
while(1)
{
p_sem(sem_id,0);

printf("i am child\n");
printf("child_flag=%d\n",_flag);
printf("c_hello ");
sleep(2);
printf("c_world!\n");
sleep(2);

v_sem(sem_id,0);
}

}
else
{
while(1)
{
/* 获得信号量集中编号为0的资源*/
p_sem(semid,0);

/*************临界区 *****************************************************/
printf("i am father\n");
printf("father_flag=%d\n",_flag);
printf("f_creat ");
sleep(2);
printf("sucess!\n");
sleep(2);
/*************临界区 *****************************************************/

/* 释放资源*/
v_sem(semid,0);

}
wait(0);

}
destroy(semid);
return 0;

}

makefille文件:

all:main clear
main:sem.c main.c
gcc sem.c main.c -o main

clear:
rm -rf *.o
运行结果:
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: