目錄題目解析代碼展示process_A.cprocess_B.cprocess_C.c結果展示重要知識點記錄 題目 設計一個程式,作為進程A,進程A專門創建一個信號量集,要求信號量集中有1個信號量,對信號量集合中的信號量進行設置,要求集合中的信號量的初值為1,然後再設計2個程式,分別是進程B和進程C ...
目錄
題目
設計一個程式,作為進程A,進程A專門創建一個信號量集,要求信號量集中有1個信號量,對信號量集合中的信號量進行設置,要求集合中的信號量的初值為1,然後再設計2個程式,分別是進程B和進程C,要求進程B和進程C使用進程A創建的信號量集合中的信號量實現互斥訪問。 提示:進程A、進程B、進程C需要使用共用記憶體作為臨界資源的訪問。
解析
該題目核心設計思路是利用信號量集的P操作和V操作,實現進程B與進程C之間的互斥,避免進程B與進程C同時對共用記憶體段操作。三個進程文件具體分工如下:
- 進程A用於創建並初始化信號量集與共用記憶體中的初始數據值
- 進程B用於更改共用記憶體段中的數據值
- 進程C用於輸出共用記憶體段中的數據值
代碼展示
process_A.c
/*******************************************************************
*
* file name: process_A.c
* author : [email protected]
* date : 2024/05/28
* function : 該案例是掌握進程通信方式,主要是共用記憶體和信號量集的使用
* 進程A需要創建一個信號量集,該信號量集中有一個信號量,
* 並要求該信號量的初值為1;進程A還需要創建一個共用記憶體段,
* 供給進程B和進程C進行訪問操作
* note : None
* version :
*
* CopyRight (c) 2023-2024 [email protected] All Right Reseverd
*
* *****************************************************************/
/****************************頭文件**************************************/
#include <stdio.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
/****************************聯合體**************************************/
union semun
{
int val;
struct semid_ds *buf;
unsigned short *array;
} ;
int main(int argc, char const *argv[])
{
/****創建共用記憶體段,並完成數據的寫入****/
//1. 申請共用記憶體段
int shm_id = shmget(ftok(".", 0xffffff01), 4, IPC_CREAT | IPC_EXCL | 0644);
if(shm_id == -1)
{
fprintf(stderr, "shmget error, errno:%d, %s\n", errno, strerror(errno));
shm_id = shmget(ftok(".", 0xffffff01), 4, 0644);
}
//2. 映射共用記憶體到進程A中
int *pshm = (int *)shmat(shm_id, NULL, 0);
if(pshm == (void*)-1)
{
fprintf(stderr, "shmat error, errno:%d, %s\n", errno, strerror(errno));
exit(-1);
}
//3. 向共用記憶體中寫入數據
*pshm = 0;
//4. 分離共用記憶體段
int flag_dt = shmdt(pshm);
if(flag_dt == -1)
{
fprintf(stderr, "shmdt error, errno:%d, %s\n", errno, strerror(errno));
exit(-1);
}
/****創建信號量集,並設置信號量集的信號量初值為1****/
//1. 創建信號量集
int sem_id = semget(ftok(".", 0xffffff01), 1, IPC_CREAT | IPC_EXCL | 0644);
if(sem_id == -1)
{
fprintf(stderr, "sem_id error, errno:%d, %s\n", errno, strerror(errno));
sem_id = semget(ftok(".", 0xffffff01), 1, 0644);
}
//2. 先獲取信號集中的數據,再設置信號量初值為1
union semun arg;
arg.val = 1;
semctl(sem_id, 0,SETVAL,arg.val);
return 0;
}
process_B.c
/*******************************************************************
*
* file name: process_B.c
* author : [email protected]
* date : 2024/05/28
* function : 該案例是掌握進程通信方式,主要是共用記憶體和信號量集的使用
* 需要將進程A創建的共用記憶體段映射到進程B中,方便後續寫入數據;
* 進程B需要對進程A創建的信號量集交替進行P操作和V操作,來實現
* 對共用記憶體段中的數據互斥修改
* note : None
* version :
*
* CopyRight (c) 2023-2024 [email protected] All Right Reseverd
*
* *****************************************************************/
/****************************頭文件**************************************/
#include <stdio.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{
while(1)
{
/****打開信號量集,完成P操作****/
//1. 打開信號量集
int sem_id = semget(ftok(".", 0xffffff01), 1, 0644);
if(sem_id == -1)
{
fprintf(stderr, "sem_id error, errno:%d, %s\n", errno, strerror(errno));
exit(-1);
}
//2. 定義結構體變數,並對結構體變數值完成相應配置
struct sembuf semop_P;
semop_P.sem_num = 0; //該信號量集只有一個信號量,所以從下標0開始
semop_P.sem_op = -1; //操作值為負值,代表執行P操作,向信號量集申請資源
semop_P.sem_flg = 0; //由於題目要求進程B與進程C互斥,所以標誌設為0,即預設阻塞模式
//3. 對信號量集完成P操作
semop(sem_id, &semop_P, 1);
/****打開共用記憶體段,並完成數據的寫入****/
//1. 打開共用記憶體段
int shm_id = shmget(ftok(".", 0xffffff01), 4, 0644);
if(shm_id == -1)
{
fprintf(stderr, "shmget error, errno:%d, %s\n", errno, strerror(errno));
exit(-2);
}
//2. 映射共用記憶體到進程B中
int *pshm = (int *)shmat(shm_id, NULL, 0);
if(pshm == (void*)-1)
{
fprintf(stderr, "shmat error, errno:%d, %s\n", errno, strerror(errno));
exit(-3);
}
//3. 每次完成P操作後,將共用記憶體中的數據加一
*pshm += 1;
//4. 分離共用記憶體段
int flag_dt = shmdt(pshm);
if(flag_dt == -1)
{
fprintf(stderr, "shmdt error, errno:%d, %s\n", errno, strerror(errno));
exit(-4);
}
/****完成對共用記憶體中數據修改後,執行V操作****/
//1. 定義結構體變數,並對結構體變數值完成相應配置
struct sembuf semop_V;
semop_V.sem_num = 0; //該信號量集只有一個信號量,所以從下標0開始
semop_V.sem_op = +1; //操作值為正值,代表執行V操作,向信號量集歸還資源
semop_V.sem_flg = 0; //由於題目要求進程B與進程C互斥,所以標誌設為0,即預設阻塞模式
//2. 對信號量集完成V操作
semop(sem_id, &semop_V, 1);
//為了方便觀察結果,延遲一秒在進入迴圈
sleep(1);
}
return 0;
}
process_C.c
/*******************************************************************
*
* file name: process_C.c
* author : [email protected]
* date : 2024/05/28
* function : 該案例是掌握進程通信方式,主要是共用記憶體和信號量集的使用
* 需要將進程A創建的共用記憶體段映射到進程C中,方便後續讀出數據;
* 進程C需要對進程A創建的信號量集交替進行P操作和V操作,來實現
* 對共用記憶體段中的數據互斥修改
* note :
* 由於信號量集中的信號量初值設定為1,所以進程B與進程C的執行順序
* 會影響輸出結果。若是想要從共用記憶體段中數據初值開始輸出,則需要
* 先執行進程C,在執行進程B
* version :
*
* CopyRight (c) 2023-2024 [email protected] All Right Reseverd
*
* *****************************************************************/
/****************************頭文件**************************************/
#include <stdio.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{
while(1)
{
/****打開信號量集,完成P操作****/
//1. 打開信號量集
int sem_id = semget(ftok(".", 0xffffff01), 1, 0644);
if(sem_id == -1)
{
fprintf(stderr, "sem_id error, errno:%d, %s\n", errno, strerror(errno));
exit(-1);
}
//2. 定義結構體變數,並對結構體變數值完成相應配置
struct sembuf semop_P;
semop_P.sem_num = 0; //該信號量集只有一個信號量,所以從下標0開始
semop_P.sem_op = -1; //操作值為負值,代表執行P操作,向信號量集申請資源
semop_P.sem_flg = 0; //由於題目要求進程B與進程C互斥,所以標誌設為0,即預設阻塞模式
//3. 對信號量集完成P操作
semop(sem_id, &semop_P, 1);
/****打開共用記憶體段,並完成數據的輸出****/
//1. 打開共用記憶體段
int shm_id = shmget(ftok(".", 0xffffff01), 4, 0644);
if(shm_id == -1)
{
fprintf(stderr, "shmget error, errno:%d, %s\n", errno, strerror(errno));
exit(-2);
}
//2. 映射共用記憶體到進程B中
int *pshm = (int *)shmat(shm_id, NULL, 0);
if(pshm == (void*)-1)
{
fprintf(stderr, "shmat error, errno:%d, %s\n", errno, strerror(errno));
exit(-3);
}
//3. 每次完成P操作後,將共用記憶體段中的數據輸出到終端上
printf("data = %d\n", *pshm);
// 4. 分離共用記憶體段
int flag_dt = shmdt(pshm);
if(flag_dt == -1)
{
fprintf(stderr, "shmdt error, errno:%d, %s\n", errno, strerror(errno));
exit(-4);
}
/****完成對共用記憶體中數據輸出後,執行V操作****/
//1. 定義結構體變數,並對結構體變數值完成相應配置
struct sembuf semop_V;
semop_V.sem_num = 0; //該信號量集只有一個信號量,所以從下標0開始
semop_V.sem_op = +1; //操作值為正值,代表執行V操作,向信號量集歸還資源
semop_V.sem_flg = 0; //由於題目要求進程B與進程C互斥,所以標誌設為0,即預設阻塞模式
//2. 對信號量集完成V操作
semop(sem_id, &semop_V, 1);
//為了方便觀察結果,延遲一秒在進入迴圈
sleep(1);
}
return 0;
}
結果展示
重要知識點記錄
修改信號量集中的信號量的初值,需要使用到SETVAL標識,具體操作如下圖: