(P30)system v信號量

1.信號量

  • 信號量和P,V原語由Dijkstra提出
  • 信號量
    (1)互斥問題: P,V在同一個進程中
    (2)同步問題:P,V在不同進程中
  • 信號量值含義,S表示計數值
    (1)S>0:S表示可用資源的個數
    (2)S=0:表示無可用資源,無等待進程
    (3)S<0:|S|表示等待隊列中進程個數,即:若當前資源計數值S=0,此時來一個進程申請資源,計數值減去1爲-1,|-1|=1表示等待隊列中的進程個數爲1
  • 信號量數據結構
struct semaphore
{
	int value;//信號量計數值S
	pointer_PCB queue;//將等待進程的控制塊指針放到等待隊列中
}
  • P原語:進程申請資源
    原語:這塊代碼是原子性的,不會被其它信號所中斷,在硬件上,實際是通過關閉中斷的方式來實現的。
P(s)
{
	s.value=s.value--;
	if (s.value<0)
	{
		該進程狀態置爲等待狀態;
		將該進程的PCB插入相應的等待隊列s.queue末尾
	}
}
  • V原語:進程歸還資源
    若之前s.value<0說明有進程在等待資源,此時s.value++歸還一個資源,意味着要喚醒一個進程
V(s)
{
	s.value=s.value++;
	if (s.vaue <=0)
	{
		喚醒相應等待隊列s.queue中等待的一個進程,
		改變其狀態爲就緒態;
		並將其插入就緒隊列中;
	}
}

2.信號量集結構

  • 信號量集結構struct semid_ds
struct semid_ds {
	//IPC對象都有的
    struct ipc_perm sem_perm;  /* Ownership and permissions */
	
	//信號量集所特有
    time_t          sem_otime; /* Last semop time *///最後一次執行PV操作的時間
    time_t          sem_ctime; /* Last change time *///信號量集最後一個改變的時間
    unsigned long   sem_nsems; /* No. of semaphores in set *///信號量集中的信號量的個數
};

3.信號量集函數

  • 消息隊列和共享內存有4個,而信號量集只有三個,因爲semop涵蓋了P和V操作
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

//創建或者打開一個信號量集
int semget(key_t key, int nsems, int semflg);

//控制一個信號量集
int semctl(int semid, int semnum, int cmd, ...);

int semop(int semid, struct sembuf *sops, size_t nsops);
  • semget函數
功能:用來創建和訪問一個信號量集

原型:
int semget(key_t key, int nsems, int semflg);

參數:
key:信號集的名字
nsems:信號集中信號量的個數
semflg:由9個權限標誌構成,他們的用法和創建文件時使用的mode模式標誌是一樣的

返回值:
成功返回一個非負整數,即:該信號集的標識碼;
失敗返回-1
  • shmctl函數
功能:用於控制信號量集

原型:
int semctl(int semid, int semnum, int cmd, ...);

參數:
semid:由semget返回的信號集標識碼
semnum:信號集中信號量的序號
cmd:將要採取的動作(3)
最後一個參數根據命令不同而不同

返回值:
成功返回0;
失敗返回-1
  • cmd
    在這裏插入圖片描述
  • eg:權限perms是666,信號量集中信號量的個數nsems爲1
    在這裏插入圖片描述
刪除信號量集:
ipcrm -S key,eg:ipcrm -S 0x4d2
ipcs -Q semid
  • eg:NetworkProgramming-master (1)\NetworkProgramming-master\P30sem.cpp
/
// Created by wangji on 19-8-13.
//

// p30 system v信號量(一)

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


#include <stdlib.h>
#include <stdio.h>
#include <errno.h>

// https://blog.csdn.net/a1414345/article/details/64513946

#define ERR_EXIT(m) \
        do \
        { \
             perror(m); \
             exit(EXIT_FAILURE);    \
        } while (0);

//來自man semctl
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) */
};

// 僅僅創建信號量集
int sem_creat(key_t key)
{
    int semid;
    semid = semget(key, 1, IPC_CREAT | IPC_EXCL | 0666);//IPC_EXCL表示只能創建1次
    if (semid == -1)
    {
        ERR_EXIT("semget");
    }
    return semid;//返回信號量集的id
}

//僅僅打開一個創建的信號量集
int sem_open(key_t key)
{
    int semid;
    semid = semget(key, 0, 0);//由於信號量集已經存在了,可以不指定信號量的個數;打開選項也可以不必關心
    if (semid == -1)
    {
        ERR_EXIT("semget");
    }
    return semid;
}

// 設置信號量中信號量的值
int sem_setval(int semid, int val)
{
    union semun su;
    su.val = val;
    int ret;
    ret = semctl(semid, 0, SETVAL, su);
    if (ret == -1)
    {
        ERR_EXIT("setval")
    }
    return 0;
}

// 獲取信號量中信號量的值
int sem_getval(int semid)
{
    int ret;
    ret = semctl(semid, 0, GETVAL,0);//第4個參數忽略了,填寫0
    if (ret == -1)
    {
        ERR_EXIT("getval")
    }
    printf("sem.val = %d\n", ret);
    return ret;
}

//只能刪除信號量集,不能刪除信號量集中的某個信號量
int sem_d(int semid)
{
    int ret;
    ret = semctl(semid, 0, IPC_RMID, NULL);//信號量個數不知道的話填寫0
    if (ret == -1)
    {
        ERR_EXIT("rm_sem")
    }
    return 0;
}

int main(int argc, char** argv)
{
    int opt;
   
    int semid;
    semid=sem_creat(1234);
    sleep(5);//過5s刪除該信號量集
    sem_d(semid);
   
 }
  • 測試:執行:./sem,過5s後,執行ipcs發現信號量集會被刪除
    在這裏插入圖片描述
    在這裏插入圖片描述

2902

4.信號量eg

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章