信号量(2/2)_有名信号量

有名信号量
有名信号量的特点是把信号量的值保存在文件中。
这决定了它的用途非常广:既可以用于线程,也可以用于相关进程间,甚至是不相关进程。
(a)有名信号量能在进程间共享的原因
由于有名信号量的值是保存在文件中的,所以对于相关进程来说,子进程是继承了父
进程的文件描述符,那么子进程所继承的文件描述符所指向的文件是和父进程一样的,当
然文件里面保存的有名信号量值就共享了。
(b)有名信号量相关函数说明
有名信号量在使用的时候,和无名信号量共享sem_wait和sem_post函数。
区别是有名信号量使用sem_open代替sem_init,另外在结束的时候要像关闭文件
一样去关闭这个有名信号量。

(1)打开一个已存在的有名信号量,或创建并初始化一个有名信号量。一个单一的调用就完
成了信号量的创建、初始化和权限的设置。
sem_t *sem_open(const char *name, int oflag, mode_t mode , int value);
name是文件的路径名;
Oflag 有O_CREAT或O_CREAT|O_EXCL两个取值;
mode_t控制新的信号量的访问权限;
Value指定信号量的初始化值。
注意:
这里的name不能写成/tmp/aaa.sem这样的格式,因为在linux下,sem都是创建
在/dev/shm目录下。你可以将name写成“/mysem”或“mysem”,创建出来的文件都
是“/dev/shm/sem.mysem”,千万不要写路径。也千万不要写“/tmp/mysem”之类的。
当oflag = O_CREAT时,若name指定的信号量不存在时,则会创建一个,而且后
面的mode和value参数必须有效。若name指定的信号量已存在,则直接打开该信号量,

同时忽略mode和value参数。当oflag = O_CREAT|O_EXCL时,若name指定的信号量已存在,

该函数会直接返回error。

(2) 一旦你使用了一信号量,销毁它们就变得很重要。
在做这个之前,要确定所有对这个有名信号量的引用都已经通过sem_close()函数
关闭了,然后只需在退出或是退出处理函数中调用sem_unlink()去删除系统中的信号量,
注意如果有任何的处理器或是线程引用这个信号量,sem_unlink()函数不会起到任何的作用。
也就是说,必须是最后一个使用该信号量的进程来执行sem_unlick才有效。因为每个
信号灯有一个引用计数器记录当前的打开次数,sem_unlink必须等待这个数为0时才能把

name所指的信号灯从文件系统中删除。也就是要等待最后一个sem_close发生。

(c)有名信号量在无相关进程间的同步

前面已经说过,有名信号量是位于共享内存区的,那么它要保护的资源也必须是位于
共享内存区,只有这样才能被无相关的进程所共享。
在下面这个例子中,服务进程和客户进程都使用shmget和shmat来获取得一块共享内

存资源。然后利用有名信号量来对这块共享内存资源进行互斥保护。


下面的例子展示了有名信号量在无关进程间同步,同时使用了共享内存进行进程间通信。

先启动server,再启动client。

例子:server.c

#include <sys/types.h>
#include <string.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <semaphore.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define SHMSZ 270
char SEM_NAME[]= "aa";

int main()
{
    char ch;
    int shmid;
    key_t key;
    char *shm,*s;
    sem_t *mutex;
    //name the shared memory segment
    key = 1000;
    //create & initialize semaphore
    mutex = sem_open(SEM_NAME,O_CREAT,0644,2);
    if(mutex == SEM_FAILED)
    {
        perror("unable to create semaphore");
        sem_unlink(SEM_NAME);
        exit(-1);
    }
    //create the shared memory segment with this key
    shmid = shmget(key,SHMSZ,IPC_CREAT|0666);
    if(shmid<0)
    {
        perror("failure in shmget");
        exit(-1);
    }
    //attach this segment to virtual memory
    shm = shmat(shmid,NULL,0);
    //start writing into memory
    s = shm;
    
    memset(s,'\0',SHMSZ);
    
    int n=20;
    for(;n>-1;n--)
    {
        sem_wait(mutex);
        
        printf("server-step:%d,s:%s\n",n,s);
        
        if(NULL!=strchr(s,'*'))
            break;
        
        sem_post(mutex);
        
        sleep(1);
    }
    
    sem_close(mutex);
    sem_unlink(SEM_NAME);
    shmctl(shmid, IPC_RMID, 0);
    exit(0);
}


client.c

#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <semaphore.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>

#define SHMSZ 270
char SEM_NAME[]= "aa";
int main()
{
    char ch;
    int shmid;
    key_t key;
    char *shm,*s;
    sem_t *mutex;
    //name the shared memory segment
    key = 1000;
    //create & initialize existing semaphore
    mutex = sem_open(SEM_NAME,0,0644,0);
    if(mutex == SEM_FAILED)
    {
        perror("reader:unable to execute semaphore");
        sem_close(mutex);
        exit(-1);
    }
    //create the shared memory segment with this key
    shmid = shmget(key,SHMSZ,0666);
    if(shmid<0)
    {
        perror("reader:failure in shmget");
        exit(-1);
    }
    //attach this segment to virtual memory
    shm = shmat(shmid,NULL,0);
    //start reading
    s = shm;
    
    int n=10;
    for(;n>-1;n--)
    {
        sem_wait(mutex);
        
        if(n==0)
            strcat(s,"*");
        else
            strcat(s,"A");
        
        printf("client-step:%d,s:%s\n",n,s);
        
        sem_post(mutex);
        
        sleep(1);
    }
    
    //once done signal exiting of reader:This can be replaced by
    //another semaphore
    sem_close(mutex);
    shmctl(shmid, IPC_RMID, 0);
    exit(0);
}


server输出结果:


client输出结果:




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值