linux系統編程(4)

一  IPC 對象 ---- 消息隊列

IPC 對象命令

(1)查看系統中IPC對象
   ipcs  -a  顯示所有的IPC對象
   ipcs  -s/-q/-m

(2)刪除系統中的IPC對象
   ipcrm -q/-s/-m  ID

 
1.獲得key值

第一種:
key_t ftok(const char *pathname, int proj_id);
參數:
@pathname  已經存在的文件路徑
@proj_id   獲取這個整數的低8bit
返回值:
成功返回 key值,失敗返回-1


第二種:
將key值指定爲IPC_PRIVATE ,當IPC對象在親緣關係進程通信的時候


2.創建IPC對象
int msgget(key_t key, int msgflg);
參數:
@key        IPC_PRIVATE 或 ftok
@msgflg     IPC_CREAT | 0666  或 IPC_CREAT | IPC_EXCL | 0666 (判斷IPC對象是否存在)
返回值:
成功返回ID,失敗返回-1

注意:
如果對應key值的IPC對象不存在,則創建,如果存在,直接返回IPC對象的ID

3.發送消息
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
@msqid      消息隊列ID
@msgp       需要發送的消息存放的地址
@msgsz      消息正文的大小
@msgflg     0:阻塞的方式發送  IPC_NOWAIT:非阻塞方式調用
返回值:
成功返回0,失敗返回-1

消息結構體定義:

typedef struct{
    long  msg_type;   //消息類型必須在第一個位置,
    char  mtxt[1024];
    ...
}msg_t;

正文大小:sizeof(msg_t) - sizeof(long)

4.接收消息
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
參數:
@msqid   消息隊列ID
@msgp    存放接收到的消息
@msgsz   正文大小
@msgtyp  消息類型  ,  0: 總是從消息隊列中提取第一個消息
@msgflg     0:阻塞的方式接收   IPC_NOWAIT:非阻塞方式調用
返回值:
成功返回 接收消息正文大小,失敗返回-1

4.刪除消息隊列
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
參數:
@msgqid  消息隊列
@cmd     IPC_RMID(刪除消息隊列)  IPC_SET(設置消息隊列的屬性信息) IPC_STAT(獲取消息隊列屬性信息)
@buf     存放消息隊列屬性
返回值:
成功返回0,失敗返回-1

練習:
實現兩個進程通信

二 共享內存 :內核空間預留出來的一塊內存,用於進程間通信

(1)int shmget(key_t key, size_t size, int shmflg);

功能:獲取共享內存段的ID

參數:
@key    IPC_PRIVATE  或 ftok()
@size   申請的共享內存段大小 [4k的倍數]
@shmflg IPC_CREAT | 0666 或 IPC_CREAT | IPC_EXCL

返回值:
成功返回ID,失敗返回-1

(2)void *shmat(int shmid, const void *shmaddr, int shmflg);
功能:映射共享內存到用戶空間
參數:
@shmid    共享內存段ID
@shmaddr  NULL:系統自動完成映射
@shmflg   SHM_RDONLY:只讀   0:讀寫
返回值:
成功返回映射後的地址,失敗返回(void *)-1

練習:A,B通過共享內存通信

B如何知道A已經寫了數據?

flag_r  flag_w 
-------------------------------------------------------------------------------------
       |       |  數據 (從鍵盤上輸入)
-------------------------------------------------------------------------------------

(3)int shmdt(const void *shmaddr);
功能:撤銷映射
參數:
@shmaddr  共享內存映射的地址

注意:當一個進程結束的時候,它映射共享內存,會自動撤銷映射


(4)int shmctl(int shmid, int cmd, struct shmid_ds *buf);
功能:根據命令控制共享內存
參數:
@shmid  共享內存段的ID
@cmd    IPC_STAT[獲取屬性],IPC_SET[設置屬性],IPC_RMID[刪除IPC對象]
@buf    保存屬性
返回值:
成功返回0,失敗返回 -1

----------------------------------------------------------------------------
注意:當我們調用shmctl刪除共享內存的時候,並不會立即刪除。只有當共享內存映射
     次數爲0,纔會刪除共享內存對象
-----------------------------------------------------------------------------

三 信號燈(信號量)集

POSIX 線程中的同步用的是無名信號量
進程間的同步使用的是IPC 對象[信號燈集]

信號燈集:信號燈集合,每一個信號燈都可以用來表示一類資源,其值表示資源的個數

(1)創建信號燈集
int semget(key_t key, int nsems, int semflg);
參數:
@key    IPC_PRIVATE , ftok()
@nsems  信號燈集中信號燈的個數
@semflg IPC_CREAT | 0666,IPC_CREAT | IPC_EXCL
返回值:
成功返回ID,失敗返回-1

(2)初始化信號燈集中信號燈的值

int semctl(int semid, int semnum, int cmd, ...);
參數:
@semid   信號燈集的ID
@semnum  信號燈的編號[編號從0開始]
@cmd     SETVAL[設置信號燈的值]  ,GETVAL(獲取信號燈的值),IPC_RMID[刪除信號燈集]
返回值:
成功返回0,失敗返回-1

思考:將信號燈集中的1號信號燈初始化爲1?

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

void init_sem_value(int sem_id,int sem_num,int value)
{
    union semun sem_val;
   
    sem_val.val = value;
   
    if(semctl(sem_id,sem_num,SETVAL,sem_val) < 0)
    {
        ...
    }

    return ;
}

(3)PV操作
int semop(int semid, struct sembuf *sops, unsigned nsops);
功能:完成PV操作 
參數:
@semid  信號燈集的ID
@sops   操作方式結構體首地址
@nsops  操作信號燈的個數
返回值:
成功返回0,失敗返回-1

struct sembuf
{
    unsigned short sem_num;  /* semaphore number */
    short     sem_op;   /* semaphore operation  */
    short     sem_flg;  /* operation flags */
};

sem_op :
<1>0   等待信號燈的值變成0
<2>1   釋放資源,V操作
<3>-1  申請資源,P操作

sem_flg:
0           : 阻塞方式
IPC_NOWAIT  : 非阻塞方式調用
SEM_UNDO    : 進程結束的時候,它申請的資源自動釋放

-----------------------------------------------------------------
void P(int sem_id,int sem_num)
{
    struct sembuf sem;

    sem.sem_num = sem_num;
    sem.sem_op  = -1;
    sem.sem_flg = 0;
   
    if(semop(sem_id,&sem,1) < 0)
    {
        ....
    }
}

void V(int sem_id,int sem_num)
{
    struct sembuf sem;

    sem.sem_num = sem_num;
    sem.sem_op  = 1;
    sem.sem_flg = 0;
   
    if(semop(sem_id,&sem,1) < 0)
    {
        ....
    }
}

練習:A,B通過信號燈集同步對共享內存操作

讓創建信號燈集的進程,初始化信號燈的值 ,如果信號燈集已經存在則不初始化

sem_id = semget(key,2,IPC_CREAT | IPC_EXCL | 0666);
if(sem_id < 0)//信號燈集已經,不初始化信號燈值
{
    sem_id = semget(key,2,IPC_CREAT | 0666);

}else{
    //初始化信號燈集中信號燈的值
}
 


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