linux 进程通信 信号量

一.信号量概述
信号量的使用主要是用来保护共享资源,协调同步使用资源,使得资源在一个时刻只有一个进程(线程)所拥有。

二.信号量的分类
Linux提供两种信号量:
(1) 内核信号量,由内核控制路径使用
(2) 用户态进程使用的信号量,这种信号量又分为POSIX信号量和SYSTEM V信号量。
       POSIX信号量又分为有名信号量和无名信号量。
       有名信号量,其值保存在文件中, 所以它可以用于线程也可以用于进程间的同步。
       无名信号量,其值保存在内存中。

       POSIX 信号量与SYSTEM V信号量的比较
       1.对POSIX来说,信号量是个非负整数。常用于线程间同步。
           而SYSTEM V信号量则是一个或多个信号量的集合,它对应的是一个信号量结构体,
           这个结构体是为SYSTEM V IPC服务的,信号量只不过是它的一部分。常用于进程间同步。
       2.POSIX信号量的引用头文件是“<semaphore.h>”,而SYSTEM V信号量的引用头文件是“<sys/sem.h>”。
       3.从使用的角度,System V信号量是复杂的,而Posix信号量是简单。
           比如,POSIX信号量的创建和初始化或PV操作就很非常方便。

一)内核信号量

      待续 : https://blog.csdn.net/qinxiongxu/article/details/7830537

二)用户信号量
 1)SYSTEM V信号量

 1. man semget

       #include <sys/types.h>
       #include <sys/ipc.h>
       #include <sys/sem.h>

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

2. man semop

       #include <sys/types.h>
       #include <sys/ipc.h>
       #include <sys/sem.h>

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

       int semtimedop(int semid, struct sembuf *sops, size_t nsops,
                      const struct timespec *timeout);

3. man semctl

       #include <sys/types.h>
       #include <sys/ipc.h>
       #include <sys/sem.h>

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

semctl() performs the control operation specified by cmd on the System V semaphore set identified by semid, or on the semnum-th semaphore of that set.  (The semaphores in a set are numbered starting at 0.)

This function has three or four arguments, depending on cmd.  When there are four, the fourth has the type union semun.  The calling program must define this union as follows:

           union semun {
               int              val;              /* Value for SETVAL */
               struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
               unsigned short  *array;  /* Array for GETALL, SETALL */
               struct seminfo  *__buf;  /* Buffer for IPC_INFO
                                           (Linux-specific) */
           };

       The semid_ds data structure is defined in <sys/sem.h> as follows:

           struct semid_ds {
               struct ipc_perm sem_perm;  /* Ownership and permissions */
               time_t          sem_otime; /* Last semop time */
               time_t          sem_ctime; /* Last change time */
               unsigned long   sem_nsems; /* No. of semaphores in set */
           };

       The ipc_perm structure is defined as follows (the highlighted fields are settable using IPC_SET):

           struct ipc_perm {
               key_t          __key; /* Key supplied to semget(2) */
               uid_t          uid;   /* Effective UID of owner */
               gid_t          gid;   /* Effective GID of owner */
               uid_t          cuid;  /* Effective UID of creator */
               gid_t          cgid;  /* Effective GID of creator */
               unsigned short mode;  /* Permissions */
               unsigned short __seq; /* Sequence number */
           };

 

#include<stdio.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/sem.h>
#include<errno.h>
#include<string.h>
#include<stdlib.h>
#include<assert.h>
#include<time.h>
#include<unistd.h>
#include<sys/wait.h>
#define MAX_SEMAPHORE 1

#define FILE_BASE "msg.txt"

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

*/
union semun{
    int val;
    struct semid_ds *buf;
    unsigned short *array;
    struct seminfo *_buf;
};


static int s_sem_idx = 0;

static int g_sem_id = 0;
 
static int semaphore_create(void);
static int semaphore_set(int sem_id, int val);
static void semaphore_destory(int sem_id);
static int semaphore_p(int sem_id);
static int semaphore_v(int sem_id);

static int semaphore_create(void)
{
    key_t key;
    int semid;
    
    key = ftok(FILE_BASE,s_sem_idx++); //要想保证key一致,文件被创建后不能被删改,函数参数也必须一致
    semid = semget(key,MAX_SEMAPHORE,IPC_CREAT|0666); //创建信号量  rwx 6 110 读写
    if(semid == -1)
    {
        printf("Error in semget \n");
        s_sem_idx--;
        return -1;
        //exit(1);
    }
    printf("Semaphore have been created,ID is :%d\n",semid);

    return semid;
}
static int semaphore_set(int sem_id, int val)
{
    union semun sem_union;    
    sem_union.val = val;
    if(semctl(sem_id,0,SETVAL,sem_union)==-1)
        return 0;
    return 1;
}

static void semaphore_destory(int sem_id)
{
    //删除信号量
    union semun sem_union;
    if(semctl(sem_id,0,IPC_RMID,sem_union)==-1)
        fprintf(stderr,"Failed to delete semaphore\n");
}

static int semaphore_p(int sem_id)
{
    struct sembuf sem_b;
    sem_b.sem_num = 0;
    sem_b.sem_op = -1;
    sem_b.sem_flg = SEM_UNDO;
    if(semop(sem_id,&sem_b,1)==-1)
    {
        fprintf(stderr,"semaphore_p failed\n");
        return -1;
    }
    return 0;
}

static int semaphore_p_nowait(int sem_id)
{
      int ret = 0;
      struct sembuf sem_b;
    sem_b.sem_num = 0;
    sem_b.sem_op = -1;
    sem_b.sem_flg = IPC_NOWAIT; // 直接返回无等待,结合 error 来判断使用
    ret = semop(sem_id,&sem_b,1);
    
    if(ret != 0)
    {
        if(errno == EAGAIN)
        {
            //printf(" need wait for other process ... \n");
            return EAGAIN;
        }
        else
        {
            //printf(" semaphore_p_nowait ... \n");
            return -1;
        }
    }
     //printf(" ret = %d\n", ret);
    return 0;
}

static int semaphore_v(int sem_id)
{
    struct sembuf sem_b;
    sem_b.sem_num = 0;
    sem_b.sem_op = 1;
    sem_b.sem_flg = SEM_UNDO;
    if(semop(sem_id,&sem_b,1)==-1)
    {
        fprintf(stderr,"semaphore_v failed\n");
        return -1;
    }
    return 0;
}

int main()
{
    int pid;
    //int semid;
    int loop = 5;
    int ret = 0;
   
   g_sem_id = semaphore_create();
   semaphore_set(g_sem_id, 1);

   pid = fork();
   
   if(pid == 0)
   {
       while(loop-- > 0)
       {
               printf("0 try get sem [%d]\n", loop);
               if(semaphore_p(g_sem_id) != -1)
               {
                   printf("0 got sem [%d]\n", loop);
                   sleep(1);
                   semaphore_v(g_sem_id);
                   sleep(1);
               }
           }
   }

   pid = fork();
   
   if(pid == 0)
   {
       while(1)
       {
               //printf("2 try get sem [%d]\n", loop);
               ret = semaphore_p_nowait(g_sem_id);
               
               if(ret == EAGAIN)
               {
                   //printf(" 2 is waitting other process.sleep 1...... [%d]\n", loop);
                   continue;
               }
               else if(ret != -1)
               {
                   printf("2 got sem [%d]\n", loop);
                   sleep(1);
                   semaphore_v(g_sem_id);
                   exit(0);
               }
           }
   }

   pid = fork();
   if(pid == 0)
   {
       while(1)
       {
               //printf("3 try get sem [%d]\n", loop);
               ret = semaphore_p_nowait(g_sem_id);
               
               if(ret == EAGAIN)
               {
                   //printf(" 3 is waitting other process.sleep 1...... [%d]\n", loop);
                   continue;
               }
               else if(ret != -1)
               {
                   printf("3 got sem [%d]\n", loop);
                   sleep(2);
                   semaphore_v(g_sem_id);
                   exit(0);
               }
           }
   }
   else if(pid >0)
   {
       while(loop-- > 0)
       {
               printf("1 try get sem [%d]\n", loop);
               if(semaphore_p(g_sem_id) != -1)
               {
                   printf("1 got sem [%d]\n", loop);
                   sleep(1);
                   semaphore_v(g_sem_id);
                   sleep(1);
               }
           }
           
   sleep(5);
   system("ipcs -a");
   semaphore_destory(g_sem_id);

   }
   else
   {
       
   }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/poject/article/details/85096146