共享内存

来源:互联网 发布:淘宝服务功能介绍 编辑:程序博客网 时间:2024/04/28 12:02

关于建立共享内存的相关函数

建立共享内存的目的在于实现进程间数据段的共享。

 

一:共享内存建立及相关函数

 

1、共享内存的使用步骤

1.1.开辟一块共享内存 shmget()
1.2.允许本进程使用共某块共享内存 shmat()
1.3.写入/读出
1.4.禁止本进程使用这块共享内存 shmdt()
1.5.删除这块共享内存 shmctl()或者命令行下ipcrm

 

2、共享内存的建立

int shmget(key_t key, size_t size, int shmflg);

key:建立共享内存的键值,该值是可以自己设定的,当有信号量时,该值是信号量返回的键值。

size:建立共享内存的大小;

shmflg:建立共享内存的权限。如:0666 | IPC_CREAT

返回建立共享内存的描述符。

 

3、共享内存的获取

void *shmat(int shmid, const void *shmaddr, int shmflg);

shmid:shmget()函数返回的共享内存的描述符。

shmaddr:是共享内存的起始地址,可以为空。
shmflag:是本进程对该内存的操作模式。如果是SHM_RDONLY的话,就是只读模式。其它的是读写模式
成功时,这个函数返回共享内存的起始地址。失败时返回-1。

 

4、共享内存的禁用

int shmdt(const void *shmaddr);

shmdt()与shmat()相反,是用来禁止本进程访问一块共享内存的函数。
参数char *shmaddr是那块共享内存的起始地址。
成功时返回0。失败时返回-1。

 

5、共享内存的删除

int shmctl(int shmid, int cmd, struct shmid_ds *buf);

shmid:共享内存描述符

cmd:操作共享内存的命令

IPC_STAT 得到共享内存的状态
IPC_SET 改变共享内存的状态
IPC_RMID 删除共享内存

buf:IPC_STAT的时候,取得的状态放在这个结构体中。如果要改变共享内存的状态,用这个结构体指定.

 

二、共享内存信号量

建立共享内存后,各个进程可能会对共享内存同时操作,为了保证各个进程正常的使用共享内存,采用信号量,保证各个进程间有序的使用共享内存。

 

1、生成信号量描述符

key_t ftok(const char *pathname, int proj_id);

pathname: 一般用当前进程的程序名

proj_id:标记这个标识符所标识的共享内存是这个进程所开辟的第几个共享内存

ftok()会返回一个key_t型的值,也就是计算出来的标识符的值。

 

2、信号量的获取

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

key:ftok()函数创建的键值

nsems:建立信号量的个数

semflg:建立信号量的标志。如:IPC_EXCL | IPC_CREAT | 0660

返回值:如果成功,则返回信号量集的IPC标识符。如果失败,则返回-1:errno=EACCESS(没有权限)
EEXIST(信号量集已经存在,无法创建)
EIDRM(信号量集已经删除)
ENOENT(信号量集不存在,同时没有使用IPC_CREAT)
ENOMEM(没有足够的内存创建新的信号量集)
ENOSPC(超出限制)

 

2、信号量的操作

int semop(int semid,struct sembuf*sops,unsign ednsops);
semid:semget()返回的描述符

sops:指向将要操作的数组的指针

ednsops:数组中的操作的个数。

struct sembuf

{
     ushort  sem_num;     /*semaphore index in array*/
     short    sem_op;        /*semaphore operation*/
     short    sem_flg;       /*operation flags*/

}
sem_num将要处理的信号量的个数。
sem_op要执行的操作。
sem_flg操作标志。

如果sem_op是负数,那么信号量将减去它的值.如果sem_op是正数,则信号量加上它的值.如果sem_op是0,那么调用进程将调用sleep(),直到信号量的值为0。这在一个进程等待完全空闲的资源时使用。

。如果没有使用IPC_NOWAIT,那么调用进程将进入睡眠状态,直到信号量控制的资源可以使用为止。

返回值:

0,如果成功。-1,如果失败:errno=E2BIG(nsops大于最大的ops数目)
EACCESS(权限不够)
EAGAIN(使用了IPC_NOWAIT,但操作不能继续进行)
EFAULT(sops指向的地址无效)
EIDRM(信号量集已经删除)
EINTR(当睡眠时接收到其他信号)
EINVAL(信号量集不存在,或者semid无效)
ENOMEM(使用了SEM_UNDO,但无足够的内存创建所需的数据结构)
ERANGE(信号量值超出范围)

 

3、信号量的控制

int semctl(int semid,int semnum,int cmd,union semunarg);
semid:获取的信号量的id;

semnum:在信号量中的位置

cmd:控制命令

     IPC_STAT读取一个信号量集的数据结构semid_ds,并将其存储在semun中的buf参数中。
    ·IPC_SET设置信号量集的数据结构semid_ds中的元素ipc_perm,其值取自semun中的buf参数。
    ·IPC_RMID将信号量集从内存中删除。
    ·GETALL用于读取信号量集中的所有信号量的值。
    ·GETNCNT返回正在等待资源的进程数目。
    ·GETPID返回最后一个执行semop操作的进程的PID。
    ·GETVAL返回信号量集中的一个单个的信号量的值。
    ·GETZCNT返回这在等待完全空闲的资源的进程数目。
    ·SETALL设置信号量集中的所有的信号量的值。
    ·SETVAL设置信号量集中的一个单独的信号量的值。

semunarg:表示设定的值。

例子:

int get_sem_val(intsid,intsemnum)
{
     return(semctl(sid,semnum,GETVAL,0));
}
 下面是一个实际应用的例子:
#defineMAX_PRINTERS5
printer_usage()
{
      int x;
      for(x=0;x<MAX_PRINTERS;x++)
      printf("Printer%d:%d/n/r",x,get_sem_val(sid,x));
}
下面的程序可以用来初始化一个新的信号量值:
void init_semaphore(int sid,int semnum,int initval)
{
     union semunsemopts;
     semopts.val=initval;
     semctl(sid,semnum,SETVAL,semopts);
}

 

例子上传。

 

 

原创粉丝点击