問題:
三個程序P1、P2、P3互斥使用一個包含N(N>0)個單元的緩沖區。P1每次用produce()生成一個正整數并送入緩沖區某一空單元中;P2每次用getodd()從該緩沖區中取出一個奇數并用countodd()統計奇數個數;P3每次用geteven()從該緩沖區中取出一個偶數并用counteven()統計偶數個數。
1.設計問題
1)設計多程序分别執行不同代碼塊
2)使用信号量PV操作控制多程序進行互斥執行
3)使用共享記憶體實作緩沖區
2.解決問題
1)實作多程序分别執行不同代碼塊
/*
============================================================================
Name : createMultiprocess.c
Author : lingo
Version :
CreateDate : 2018下午9:03:24
============================================================================
*/
#include <stdio.h>
#include <unistd.h>
int main(int arg,char* argv[]){
int tog;
// 設定fork傳回值
pid_t pid;
// 建立多個子程序,childNum為子程序個數
int i,childNum;
for(i = 0,childNum = 3;i < childNum;i++){
pid = fork();
// 是父程序 continue ,for()五次,若是子程序,break該for循環,即子程序無需經曆for循環
if(pid==0 || pid<0) break;
}
if(pid < 0){
printf("ERROR:fork child process failure\n");
}
// 子程序循環體
else if(pid == 0){
//共同執行代碼
tog = 10;
//分别執行代碼區
if(i == 0){
printf("i=%i tog=%u\n",i,tog);
}else if(i == 1){
printf("i=%i tog=%u\n",i,tog);
}else if(i == 3){
printf("i=%i tog=%u\n",i,tog);
}
printf("create sub process id: %d, parent id: %d\n", getpid(), getppid());
// pause 子程序進入睡眠,即阻塞住所有子程序,直到被信号(signal)所中斷.
//while(1) pause();
}
// 父程序執行體
else{
//tog = 10;
printf("tog=%u",tog);
printf("Parent process %d sleep 1 s\n", getpid());
sleep(3);
}
return 0;
}
2)實作初始化信号量和對信号量PV操作,封裝為mysem.h頭檔案供使用
/*
* mysem.h
*
* Created on: 2018年10月19日
* Author: lin
*/
#ifndef MYSEM_H_
#define MYSEM_H_
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
// 定義信号量結構
union semaphore{
int val;
struct semid_ds *buf;
unsigned short *array;
};
/*聲明函數*/
/*初始化信号量
* sem_id 信号量的辨別id
* init_val 信号量的pv操作的數值
* */
int init_sem(int sem_id,int init_val){
union semaphore sem;
sem.val = init_val; //設定初值
if(semctl(sem_id,0,SETVAL,sem)==-1){
printf("init semaphore error \n");
return -1;
}
return 0;
}
/*删除指定辨別id的信号量*/
int del_sem(int sem_id){
union semaphore sem;
if(semctl(sem_id,0,IPC_RMID,sem)==-1){
return -1;
}
return 0;
}
/* 将指定辨別的信号量-1 若信号量值為0時執行p操作的程序會處于阻塞等待的狀态*/
int P(int sem_id){ //信号量-1
struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = -1;
sem_b.sem_flg = SEM_UNDO;
if(semop(sem_id,&sem_b,1)==-1){
return -1;
}
return 0;
}
/* 将指定辨別的信号量+1 若型号量的值為0執行完v操作後 喚醒處于阻塞等待的程序處于就緒狀态等待cpu調用*/
int V(int sem_id){ //信号量+1
struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = 1;
sem_b.sem_flg = SEM_UNDO;
if(semop(sem_id,&sem_b,1)==-1){
return -1;
}
return 0;
}
#endif /* MYSEM_H_ */
3)緩沖區結構體設計:
#define BUFF_SIZE 255
typedef struct{
int length; // 緩沖區長度
int data[BUFF_SIZE]; //緩沖區大小
int oddNum; // 記錄被get掉的奇數個數
int evenNum; // 記錄被get掉的偶數個數
}Buff;
4)共享記憶體
#include <sys/shm.h>
#define MY_SHM_ID 95551 //不同值對應不同共享記憶體,
.......
int main(){
.......
int shmid = shmget(MY_SHM_ID,sizeof(Buff),0666|IPC_CREAT);
if(shmid == -1){
printf("error semget / shmget");
}
// 映射共享記憶體
buff = (Buff*)shmat(shmid,NULL,0);
// 初始化變量
buff->length = 0;
buff->oddNum = 0;
buff->evenNum = 0;
.......
return 0;
}
3.produce(),getodd(),countodd(),geteven(),counteven()函數設計:
void produce(Buff *buff){
int temp = random(10);
buff->data[buff->length] = temp;
buff->length++;
printf("produce a num : %i \n",temp);
// 每生産一個睡眠1s
sleep(1);
}
void getodd(Buff *buff){
for(int i = 0; i < buff->length; i++){
if(1 == (buff->data[i]%2)){
printf("getodd num is : %i \n",buff->data[i]);
// 将索引的值删除,所有索引後的退位
for(int j = i; j < buff->length -1; j++){
buff->data[j] = buff->data[j+1];
}
buff->length--;
break;
}
}
}
void countodd(Buff *buff){
buff->oddNum++;
printf("Now the oddNum=%i \n",buff->oddNum);
}
void geteven(Buff *buff){
// buff 長度為1
for(int i = 0; i < buff->length; i++){
if(0 == (buff->data[i]%2)){
printf("geteven num is : %i \n",buff->data[i]);
// 将索引的值删除,所有索引後的退位
for(int j = i; j < buff->length -1; j++){
buff->data[j] = buff->data[j+1];
}
buff->length--;
break;
}
}
}
void counteven(Buff *buff){
buff->evenNum++;
printf("Now the evenNum=%i \n",buff->evenNum);
}
3. 詳細設計
源碼位址:源碼