问题:

        三个进程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. 详细设计

源码地址:源码

Logo

更多推荐