1. 程式人生 > >Linux之訊號量

Linux之訊號量

訊號量概念

Dijkstra提出的“訊號量”概念是共發程式設計領域的一項重大進步 訊號量是一種變數,它只能取正整數值,對這些正整數只能進行兩種操作:等待和訊號 用兩種記號來表示訊號量的這兩種操作:     P(semaphore variable) 代表等待     V(semaphore variable) 代表訊號

訊號量操作

首先我們對訊號量進行封裝:

//錯誤列印

void error_exit(char *errorinfo)
{
    printf("%s\n",errorinfo);
    exit(EXIT_FAILURE);
}

//訊號量建立
int  sem_create(key_t key,int nsems)
{
  int semid = semget(key,nsems,IPC_CREAT|0766);
  if(semid <0)
  {
      error_exit("creat sem error");
  }
  return semid;
}

//訊號量的開啟

int sem_myopen(key_t key)
{
  int semid = semget(key,0,0);
  if(semid <0)
  {
      error_exit("creat sem error");
  }
  return semid;
}

//訊號量刪除
int sem_delete(int semid)
{
  int ret = semctl(semid,0,IPC_RMID);
  if(ret<0)
  {
      error_exit("delete sem error");
  }
  return ret;
}

//訊號量設定裡面的值

int sem_setval(int semid,int nsempos,int val)
{
    union semun arg;
    arg.val=val;
    int ret=semctl(semid,nsempos,SETVAL,arg); 
    if(ret<0)
    {
       error_exit("set value error");
    }
    return ret;
}

//訊號量獲取裡面的值
int sem_getval(int semid,int nsempos)
{
    int value=semctl(semid,nsempos,GETVAL); 
    if(value<0)
    {
       error_exit("get value error");
    }
    return value;
}

//訊號量設定
int sem_setall(int semid,unsigned short*values)
{
     union semun arg;
     arg.array=values;
    int ret=semctl(semid,0,SETVAL,values); 
    if(ret<0)
    {
       error_exit("set all error");
    }
    return ret;
}

//訊號量獲取
int sem_getall(int semid,unsigned short*values)
{
     union semun arg;
     arg.array=values;
    int ret=semctl(semid,0,GETVAL,values); 
    if(ret<0)
    {
       error_exit("set all error");
    }
    return ret;
}

//訊號量V操作
int sem_v(int semid,int npos)
{
   struct sembuf buf={npos,1,0};
   int ret=semop(semid,&buf,1);
   if (ret<0)
   {
        error_exit("sem p error");
   }
   return ret;
}

//訊號量P操作
int sem_p(int semid,int npos)
{
   struct sembuf buf={npos,-1,0};
   int ret=semop(semid,&buf,1);
   if (ret<0)
   {
        error_exit("sem p error");
   }
   return ret;
}

簡單使用上面封裝的函式實現 父子程序上鎖

int main()
{
    int semid= sem_create((key_t)0002,1);
    sem_setval(semid,0,0);
    int pid =fork();
    //父程序
    if(pid>0)
    {
        while(1)
        {
            printf("parent working\n");
            sleep(5);
            sem_v(semid,0);
        }
    }
    //子程序
    else if(pid==0)
    {
       while(1)
       {
           printf("child wait\n");
           sem_p(semid,0);
           printf("child working\n");
       }
    }
    else
    {
       perror("fork error\n");
    }
    return 0;
}

實現結果:(每次執行完一個程序才會執行下一個程序,可用於兩程序協同處理事情的時候進行使用)

使用以上封裝的函式實現多程序p和v的操作

int main()
{
     int semid=sem_create((key_t)0001,1);
     sem_setval(semid,0,10);
     fork();
     fork();
     fork();
     fork();
     fork();
     fork();
     sleep(1);
     printf("my name is %d\n",getpid());
     sem_p(semid,0);
     printf("%d get\n",getpid());
     sleep(5);
     printf("%d done\n",getpid());
     sem_v(semid,0);
     return 0;
}

結果:

上面結果:fork6次,總共64個程序,如同64個人練車一樣,但是隻有10輛車(set_value的第三個引數設定了10),使用p操作代表車被用了一輛,v代表車使用完讓出來給別人用,這就是生產者和消費者模型,進行資源保護