Linux共享內存的使用(二)

在上篇中我們講到了共享內存的操作,沒有看的童鞋可以點擊鏈接:
Linux共享內存的使用(一)

信號量

信號量是一個內存變量,可以被系統中的任何進程所訪問。

爲什麼引入信號量

大家可以考慮這個問題...
    在使用共享內存的時候,如果客戶端在讀取數據時,恰好服務器端也在寫數據,那麼就會出現問題。
如何解決呢?
    出現讀寫衝突的問題,可通過信號量機制,保證讀寫共享內存段互斥進行加以解決。

linux中的信號量

Linux中信號量是以集合的形式存在的,一個集合中存在着多個信號量。

信號量的操作函數

    功能     創建一個信號量集合
    頭文件   #include<sys/sem.h>
    函數原型
    int semget(key_t key, int nsems, int flag);

    key         創建信號量集的鍵值

    nsems       集合中信號量的個數

    flag        信號量集的權限

    返回值       >0      信號量集的ID
                -1      失敗 
    功能     操作信號量集合
    頭文件   #include<sys/sem.h>
    函數原型
    int semctl(int semid, int semnum, int cmd, union semun arg);

    semid       信號量集ID

    semnum      要操作的信號量序號

    cmd         要執行的命令

    IPC_STAT    取信號量集的屬性,存放在arg.buf所指單元
    IPC_SET     按arg.buf所指單元的數據設置信號量集合中的
                sem_perm.uid、sem_perm.gid、sem_perm.mode
                三個屬性。
    IPC_RMID    刪除該信號量集合
    GETVAL      返回第semnum個信號量的semval值
    SETVAL      用arg.val設置第semnum個信號量的semval值
    GETALL      取信號量集所有信號量的值,存放在arg.array指向的
                數組中 
    SETALL      按照arg.array所指數組的值設置信號量集中所有信號
                量的值

    arg         修改信號量時所需的數據或獲取信號量數據時所需的變
                量(可選)

    返回值       與cmd相關
    功能         完成信號量集的一組操作
    頭文件       #include<sys/sem.h>
    函數原型
    int semop(int semid, struct sembuf semoparr[], size_t 
    nops);

    semid       信號量集ID

    semoparr    存放一組信號量操作的數組

    nops        數組中操作的數量

    返回值        0      成功
                -1      失敗 

我們直接在上篇的基礎上,對服務器的代碼進行一些修改,客戶端代碼不變

//服務器端代碼
#include <stdio.h>
#include <stdlib.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <time.h>
#include <string.h>
#include <unistd.h>

#define SHM_KEY 99
#define SEM_KEY 88

int init_sem(int semid,int semnum,int val){ 
    union semun{
        int val;
        struct semid_ds *buf;
        unsigned short *array;
    }initval;
    initval.val=val;
    if(semctl(semid,semnum,SETVAL,initval)==-1)    {    
        perror("semctl");
        exit(1);
    }
}

void lockforwrite(int semid){
    struct sembuf action[2];
    //等待所有的讀進程都完成(進行寫操作前要保證沒有讀進程執行)
    action[0].sem_num=0;
    action[0].sem_flg=SEM_UNDO;
    action[0].sem_op=0;
    //進行寫操作(申請資源)
    action[1].sem_num=1;
    action[1].sem_flg=SEM_UNDO;
    action[1].sem_op=-1;

    if(semop(semid,action,2)==-1)    {
        perror("semop");    
        exit(1);
    }
}

void unlockafterwrite(int semid){
    struct sembuf action[1];
    //釋放寫操作資源
    action[0].sem_num=1;
    action[0].sem_flg=SEM_UNDO;
    action[0].sem_op=+1;

    if(semop(semid,action,1)==-1)    {
        perror("semop");    
        exit(1);
    }
}


int main()
{
    int seg_id,sem_id;
    char *mem_ptr;
    time_t now;
    int i=30;

    seg_id=shmget(SHM_KEY,100,IPC_CREAT|0777);
    if(seg_id==-1)
    {
        perror("shmget");
        exit(1);
    }
    mem_ptr=(char *)shmat(seg_id,0,0);
    if(mem_ptr==NULL)
    {
        perror("shmat");
        exit(1);
    }
    //(1)創建信號量集
    if((sem_id=semget(SEM_KEY,2,IPC_CREAT|0770))==-1){
        perror("semget");
        exit(1);
    }
    //(2)對信號量進行初始化
    init_sem(sem_id, 0, 0);
    init_sem(sem_id, 1, +1);
    while(i>0)
    {
        time(&now);
        puts(ctime(&now));
        //(3)對寫操作加鎖
        lockforwrite(sem_id);
        strcpy(mem_ptr,ctime(&now));
        //(4)解鎖
        unlockafterwrite(sem_id);
        sleep(1);
        i--;
    }
    shmctl(seg_id,IPC_RMID,NULL);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章