system -v 訊號量的使用

Jiangson發表於2024-04-29

訊號量的作用

訊號量是system -v IPC中的一種,透過P、V操作它體現了同步和互斥資源的分配機制。訊號量的作用主要可以總結為如下:
image
訊號量是system -v中重要的IPC,訊號量的使用例程為:
image
首先是總分總結構,即初始化、P_V函式操作、釋放資源。其中初始化是利用uion semun結構體,是一個專門就行訊號量操作的結構體。具體可以看上圖,或者在核心找。在進行P_V操作時,一般是先進行V操作再進行P操作,V操作。因為當資源不夠用即等於0的時候,V可以讓程序進入休眠狀態。
程式碼示例:
以買賣車為例子,車子和車位是一個互斥的資源。

資料實時監控.c
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/types.h>
#include <unistd.h>

#define IPC_MASK      1
#define IPC_PATH      "./"
#define RESOURCE_KIND 2

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) */
};


//建立訊號量  初始化車:0和車位:3的值
int Demo_Init();

//實時顯示資源資料 while(1)
int Real_Time_Show_Resource_Value();


int Demo_Free();



int Demo_Init()
{
    key_t key = ftok(IPC_PATH,IPC_MASK);
    if(key == -1)
    {
        perror("ftok ... ");
        return -1;
    }

    int sem_id = semget(key,RESOURCE_KIND,IPC_CREAT | 0666);
    if(sem_id == -1)
    {
        perror("semget ...");
        return -1;
    }

    printf("訊號量ID是:%d\n",sem_id);


    //初始化車和車位的值
    union semun setvalue;
    setvalue.val = 0;
    if(semctl(sem_id,0,SETVAL,setvalue) == -1)  //先設定車的值
    {
        perror("semctl ...");
        return -1;
    }

    setvalue.val = 3;
    if(semctl(sem_id,1,SETVAL,setvalue) == -1)  //先設定車位的值
    {
        perror("semctl ...");
        return -1;
    }

    return sem_id;
}


int Real_Time_Show_Resource_Value(int sem_id)
{
    int car_num   = 0;
    int car_space = 0;
    int old_car_num   = -1;
    int old_car_space = -1;
    while(1)
    {
        if((car_num = semctl(sem_id,0,GETVAL)) == -1)
        {
            perror("獲取車資料失敗!\n");
            return -1;
        }

        if((car_space = semctl(sem_id,1,GETVAL)) == -1)
        {
            perror("獲取車資料失敗!\n");
            return -1;
        }

        if(old_car_num != car_num && old_car_space != car_space)
        {
            printf("車:%d-----車位:%d\n",car_num,car_space);
            old_car_num   = car_num;
            old_car_space = car_space;
        }
    }

    return 0;
}



int main()
{
    int sem_id = Demo_Init();
    if(sem_id == -1)
    {
        perror("例程初始化失敗!\n");
        return -1;
    }

    Real_Time_Show_Resource_Value(sem_id);

    return 0;
}

買車.c
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/types.h>
#include <unistd.h>
 #include <stdlib.h>

//車下標  : 0
//位下標  : 1
int P_V_Ctrl(int sem_id,int sem_num,int ctl_num);
int P_V_Ctrl(int sem_id,int sem_num,int ctl_num)
{
    struct sembuf sb[1];

    sb[0].sem_num = sem_num;//車+1
    sb[0].sem_op  = ctl_num;
    sb->sem_flg   = 0;
    if(semop(sem_id,sb,1) == -1)
    {
        perror("semop ...");
        return -1;
    }

    return 0;
}


int main(int argc, char * argv[])
{
    if(argc != 2) return -1;

    while(1)
    {
        sleep(3);
        //車位v操作 - 1  (當資源值不夠用的時候<等於0的時候>),讓程序進入休眠態
        P_V_Ctrl(atoi(argv[1]),1,-1);
        //車p操作   + 1
        P_V_Ctrl(atoi(argv[1]),0,1);

    }

    return 0;
}

賣車.c
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/types.h>
#include <unistd.h>
 #include <stdlib.h>

//車下標  : 0
//位下標  : 1
int P_V_Ctrl(int sem_id,int sem_num,int ctl_num);
int P_V_Ctrl(int sem_id,int sem_num,int ctl_num)
{
    struct sembuf sb[1];

    sb[0].sem_num = sem_num;//車+1
    sb[0].sem_op  = ctl_num;
    sb->sem_flg   = 0;
    if(semop(sem_id,sb,1) == -1)
    {
        perror("semop ...");
        return -1;
    }

    return 0;
}


int main(int argc, char * argv[])
{
    if(argc != 2) return -1;

    while(1)
    {
        sleep(5);
        //車v操作   - 1
        P_V_Ctrl(atoi(argv[1]),0,-1);

        //車位p操作 + 1  (當資源值不夠用的時候<等於0的時候>),讓程序進入休眠態
        P_V_Ctrl(atoi(argv[1]),1,1);

    }

    return 0;
}

相關文章