前言:为了应付作业网上找的,看得懂但是不会写就很无奈orz,干脆就多加了写注解,并且修改了一下,这个是参考博客

一、设计内容

实现一个模拟shell:编写三个不同的程序:cmd1.c, cmd2.c, cmd3.c,每个程序输出一句话,分别编译成可执行文件cmd1, cmd2, cmd3。然后再编写一个程序,模拟shell程序的功能,能根据用户输入的字符串(表示相应的命令名),去为相应的命令创建子进程并让它去执行相应的程序,而父进程则等待子进程的结束,然后再等待接收下一条命令。如果接收到的命令为exit,则父进程结束,如果接收到无效命令,则显示”command not found”,继续等待。

实现一个管道通信程序:由父进程创建一个管道,然后再创建3个子进程,并由这三个子进程用管道与父进程之间进行通信:子进程发送信息,父进程等三个子进程全部发完消息后再接收信息。通信的具体内容可根据自己的需要随意设计,要求能够实验阻塞型读写过程的各种情况,并要求实现进程间对管道的互斥访问。运行程序,观察各种情况下,进程实际读写的字节数以及进程阻塞唤醒情况。

利用linux的消息队列通信机制实现两个线程间的通信:编写程序创建两个线程:sender线程和receive线程,其中sender运行函数sender(),他创建一个消息队列,然后,循环等待用户通过终端输入一串字符,将这串字符通过消息队列发送给receiver线程,直到用户输入”exit”为止;最后,它向receiver线程发送消息”end”,并且等待receiver的应答,直到应答消息后,将接收到的应答消息显示在终端上,删除相关消息队列,结束程序运行。receiver线程运行receive(),它通过消息队列接收来自sender的消息,将消息显示在终端屏幕,直到接收到”end”的消息后它向sender发送一个应答消息”over”,结束程序运行。使用无名信号量实现两个线程之间的同步与互斥。

利用linux的共享内存通信机制实现两个进程间的通信:编写程序sender,它创建一个共享内存,然后等待用户通过终端输入一串字符,并将这串字符通过共享内存发送给receiver,最后,等待receiver应答,等到应答消息后,它接收到的应答消息显示在终端屏幕上,删除共享内存,结束程序运行。编写receiver程序,它通过共享内存接收来自sender的消息,将消息显示在终端屏幕上,然后再通过该共享内存向sender发送一个应答消息”over”,结束程序的运行。使用有名信号量或System V信号量实现两个进程对共享内存的互斥使用。

二、代码实现

(1)实现一个模拟shell(感觉这个实现的很假orz)

1-1 编写cmd1.c cmd2.c cmd3.c,内容随意

//cmd1.c

#include

int main()

{

printf("this is the cmd1111111\n");

return 0;

}

//cmd2.c

#include

int main()

{

printf("this is the cmd222222\n");

return 0;

}

//cmd3.c

#include

int main()

{

printf("this is the cmd333333\n");

return 0;

}

1-2 编写Makefile(clear下面的三个rm的前面是tab,不是单纯空行)

all: myshell cmd1 cmd2 cmd3

.PHONY : clean

myshell.o : myshell.c

clean :

rm cmd1 cmd2 cmd3

rm myshell

rm *.o

1-3 编写myshell.c

#include

#include

#include

#include

#include

#include

#define CMD_COLLECTION_LEN 4 //命令数组的长度(有哪几个命令)

//command index

#define INVALID_COMMAND -1 //无效命令返回-1

#define EXIT 0

#define CMD_1 1

#define CMD_2 2

#define CMD_3 3

//bool

#define TRUE 1

char *cmdStr [CMD_COLLECTION_LEN ]= {"exit","cmd1","cmd2","cmd3"};

//对比所有命令参数,如果有一样的,就返回对应数字,用于后面执行

int getCmdIndex(char *cmd)

{

int i;

for(i=0;i

{

if (strcmp(cmd,cmdStr[i])==0)

{

return i;

}

}

return -1;

}

/*

创建子进程,这里使用了execl,后面的l表示list,即参数列表。

第一参数为path(要执行的文件路径),最后一个参数必须是NULL,

中间的为要传送的参数

*/

void myFork(int cmdIndex)

{

pid_t pid;

if((pid = fork())<0)

{

printf("创建子进程错误\n");

exit(0);

}

else if (pid == 0)

{

int execl_status = -1;

printf("子进程正在运行\n");

switch(cmdIndex)

{

case CMD_1:

execl_status = execl("./cmd1","cmd1",NULL);

break;

case CMD_2:

execl_status = execl("./cmd2","cmd2",NULL);

break;

case CMD_3:

execl_status = execl("./cmd3","cmd3",NULL);

break;

default:

printf("无此命令!!!\n");

break;

}

if(execl_status<0)

{

printf("创建错误\n");

exit(0);

}

printf("运行完毕!\n");

exit(0);

}

else{

return;

}

}

//运行cmd

void runCMD(int cmdIndex)

{

switch(cmdIndex)

{

case INVALID_COMMAND:

printf("Command Not Found \n"); //没有找到该命令

break;

case EXIT: //exit命令返回0

exit(0);

break;

default:

myFork(cmdIndex); //创建子进程运行

break;

}

}

int main()

{

pid_t pid;

char cmdStr[30]; //命令数组(最长30)

int cmdIndex; //用于显示运行哪个数据

while(TRUE)

{

printf("\n输入命令\n>>:");

scanf("%s",cmdStr);

cmdIndex = getCmdIndex(cmdStr);

runCMD(cmdIndex); //根据数字运行不同的cmd

wait(0);

}

}

1-4 编译:

make

1-5 运行截图示例:

(2)实现一个管道通信程序

2-1 编写pipe_communication.c文件

#include

#include

#include

#include

#include

#define READ 0 //filedes[0]用于读

#define WRITE 1 //filedes[1]用于写

int main() {

/*

函数原型:pipe(int filedes[2])

参数含义:filedes[0]对应管道读端,filedes[1]对应管道写端

功能:pipe在内存缓冲区中创建一个管道,并将读写该管道的一对文件描述符保存在filedes所指数组中

返回值:成功返回0,失败返回-1

*/

int filedes[2];

pid_t pid1,pid2,pid3;//pid_t本质就是int

char buf[256]; //用作read的缓冲区,保存读取的字符

pipe(filedes); //创建无名管道

if((pid1 = fork()) == -1) { //创建子进程

printf("fork error(pid1)!\n");

exit(1);

}

if(pid1 == 0) {

sleep(1); //挂起一秒

printf("正在产生子进程pid1:%d\n",getpid());

//子进程向父进程写数据,关闭管道的读端

close(filedes[READ]);

write(filedes[WRITE], "pid111111\n", strlen("pid111111\n"));

exit(0);

}

if ((pid2 = fork()) == -1) {

printf("fork error(pid2)\n");

exit(1);

}

if (pid2 == 0) {

sleep(1);

printf("正在产生子进程pid2:%d\n",getpid());

close(filedes[READ]);

write(filedes[WRITE], "pid222222\n", strlen("pid222222\n"));

exit(0);

}

if ((pid3 = fork()) == -1) {

printf("fork error(pid3)\n");

exit(1);

}

if (pid3 == 0) {

sleep(1);

printf("正在产生子进程pid3:%d\n",getpid());

close(filedes[READ]);

write(filedes[WRITE], "pid333333\n", strlen("pid333333\n"));

exit(0);

}

else {

//waitpid()会暂时停止目前进程的执行,直到有信号来或者子进程结束

pid1 = waitpid(pid1, NULL, WUNTRACED);

pid2 = waitpid(pid2, NULL, WUNTRACED);

pid3 = waitpid(pid3, NULL, WUNTRACED);

printf("main pid: %d\n",getpid());

printf("wait pid: %d %d %d 返回信息\n",pid1,pid2,pid3);

/*父进程从管道读取子进程写的数据,关闭管道的写端*/

close(filedes[WRITE]);

//read():读取的数据保存在缓冲区buf

read(filedes[READ], buf, sizeof(buf));

printf("3个子进程传输的数据为:\n%s\n", buf);

}

return 0;

}

2-2 Makefile

pipe_communication : pipe_communication.o

.PHONY : clean

clean:

rm *.o

rm pipe_communication

2-3 make编译

make

2-4 运行

(3)利用linux的消息队列通信机制实现两个线程间的通信

3.1 代码(message_queue.c)

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define TRUE 1

#define BUF_SIZE 255 //缓冲大小

//S_IRUSR|S_IWUSR:允许文件创建者读取|写入(感觉就是赋予权限)

#define PERM S_IRUSR|S_IWUSR

#define KEY_NUM 1000

typedef struct msgbuf msgbuf;

//消息缓冲区结构体

struct msgbuf

{

long mtype; //消息类型

char mtext[BUF_SIZE + 1]; //256,消息正文

};

//sem_t 信号量的数据类型,本质是个长整型的数

sem_t full;

sem_t empty;

sem_t mutex;

//pthread_t 声明线程,类似于pid_t

pthread_t write_pid;

pthread_t read_pid;

/*

IPC对象键值,每个IPC对象都关联着一个唯一的长整型的键值,

不同进程通过相同相同的键值可访问到同一个IPC对象。

若为0,创建一个新的消息队列,若大于0(通常通过ftok()生成的)

*/

key_t key;

//messageid

int msgid;

struct msgbuf msg;

//初始化

void Init()

{

/*

函数:sem_init(sem_t *sem,int pshared,unsigned int value)

参数:sem表示一个信号量,pashared(0-信号量被进程内的线程共享,非0-进程之间共享),value信号量初始值

*/

sem_init(&full,0,0);

sem_init(&empty,0,1);

sem_init(&mutex,0,1);

key = KEY_NUM;//给键值赋值

//创建消息队列

/*

函数:msgget(key_t key,int smgflag)。新教材p107

参数:key(消息队列键值,具体看上面)。msgflg(对消息队列的访问权限和控制命令的组合)

功能:如果参数msgflag为IPC_CREATE,则semget()新创建一个消息队列并返回其标识符,

或返回具有相同键值的已存在的消息队列的标识符

返回值:成功返回消息队列的标识符,失败返回-1

*/

if((msgid = msgget(key,PERM|IPC_CREAT)) == -1)

{

fprintf(stderr, "Create Message Queue Error %s\n",strerror(errno) );

exit(EXIT_FAILURE);

}

}

//读取信息

void * ReadProcess(void *arg)

{

msgbuf msg;

//init msg

msg.mtype = 1;

while(TRUE)

{

//sem_wait阻塞进程,直到信号量>=0,解除阻塞后sem值-1,表示公共资源使用后减少

sem_wait(&full);

sem_wait(&mutex);

//从消息队列获取内容

/*

函数:ssize_t msgrcv(int msqid,struct msgbuf *msgp,size_t msgsz,long msgtyp,int msgflg)

参数:msqid(消息队列的标识符),

msgp(用来存放接受到的消息内容的缓冲区指针)

msgsz(消息正文的长度),

msgtyp(接收的消息类型,0-接受消息队列中第一个消息,>0接收第一个类型为msgtyp的消息,<0接收第一个类型小于等于msgtyp的绝对值的消息)

msgflg(0-没有可接收的消息时,调用进程阻塞。其他略)

返回值:接收成功,返回实际接收到的消息正文的字节数,否则返回-1

*/

msgrcv(msgid,&msg,sizeof(msgbuf),1,0);//接收类型为1的消息(即mtype=1)

//如果接受到"end"

if(strcmp(msg.mtext,"end") == 0)

{

msg.mtype = 2;

strncpy(msg.mtext,"over",BUF_SIZE);

//msgsnd用于向标识符为msqid的消息队列发送一个消息(即发送over)

msgsnd(msgid,&msg,sizeof(msgbuf),0);

sem_post(&empty);

sem_post(&mutex);

break;

}

//print message

printf("Receive: %s\n\n",msg.mtext);

//sem_post增加信号量的值,当有线程阻塞在这个信号量时,该函数会使其中一个线程不在阻塞

sem_post(&empty);

sem_post(&mutex);

}

exit(EXIT_SUCCESS);

}

void * WriteProcess(void *arg)

{

char input[50];

msgbuf msg;

msg.mtype = 1;

while (TRUE)

{

sem_wait(&empty);

sem_wait(&mutex);

sleep(0.1);

printf("Sent: Please Input the message you want to send.\n");

scanf("%s",input);

if(strcmp(input,"exit") == 0)

{

strncpy(msg.mtext,"end",BUF_SIZE);

msgsnd(msgid,&msg,sizeof(msgbuf),0);

sem_post(&full);

sem_post(&mutex);

break; //输出exit后,转化为end,然后跳出while循环

}

strncpy(msg.mtext,input,BUF_SIZE);

msgsnd(msgid,&msg,sizeof(msgbuf),0);

printf("Sent: %s\n",msg.mtext );

//semaphore

sem_post(&full);

sem_post(&mutex);

}

// Clear Node

memset(&msg,'\0',sizeof(msgbuf));

// Block ,waiting for msg with type = 2

msgrcv(msgid,&msg,sizeof(msgbuf),2,0);

printf("Sent:%s\n",msg.mtext );

//Remove Message Queue

if( msgctl (msgid,IPC_RMID,0) == -1)

{

fprintf(stderr, "Remove Message Queue Error%s\n", strerror(errno));

exit(EXIT_FAILURE);

}

exit(EXIT_SUCCESS);

}

int main()

{

Init();

pthread_create(&write_pid,NULL,WriteProcess,NULL);

pthread_create(&read_pid,NULL,ReadProcess,NULL);

//waiting for the thread end

pthread_join(write_pid,NULL);

pthread_join(read_pid,NULL);

printf("Main Function End...\n");

return 0;

}

3-2 Makefile

message_queue : message_queue.o

cc -pthread -o message_queue message_queue.o

.PHONY : clean

clean:

rm message_queue

rm *.o

3-3 运行

make

3-4 截图

(4)利用linux的共享内存通信机制实现两个进程间的通信

4-1 Makefile

all : init sender receiver

.PHONY : clean

init : init.o common.o

cc -pthread -o init init.o common.o

sender : sender.o common.o

cc -pthread -o sender sender.o common.o

receiver : receiver.o common.o

cc -pthread -o receiver receiver.o common.o

init.o : common.h

sender.o : common.h

receiver.o : common.h

clean :

rm init

rm receiver

rm sender

rm *.o

4-2 common.h(定义一些用到的头文件)

#ifndef _COMMON_H_

#define _COMMON_H_

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

static const char *MUTEX_NAME= "mutex_shm";

static const char *FULL_NAME = "full_shm";

//static const char * PATH_NAME = "tmp/shmtemp";

//constant define

#define SHM_SIZE 1024 //输入的最大长度

#define KEY_NUM 1000

//返回共享内存的标识符

int GetShmId(key_t key);

void SemInit();

void SemDestroy();

void P(sem_t *sem);

void V(sem_t *sem);

#endif

4-3 common.c 一些公用的函数,如初始信号量等

#include "common.h"

/*

key_t GetKey(const char * pathname)

{

//int fd = open(pathname,O_CREAT,0666);

int fd = open("log.txt",O_RDWR|O_CREAT,S_IRWXU);

if(fd < 0)

{

perror("open file error");

return -1;

}

close(fd);

return ftok(pathname,0);

}

*/

int GetShmId(key_t key)

{

int shmid;

shmid = shmget(key,SHM_SIZE,IPC_CREAT|0666);

if(shmid < 0)

{

perror("Receiver: Shmget Error");

exit(EXIT_FAILURE);

}

return shmid;

}

/*

* create mutex + semaphore

* init those value

*/

void SemInit()

{

/*

* Funtion Prototype:

*

* sem_t *sem_open(const char *name, int oflag,

* mode_t mode, unsigned int value);

*

* name : MUTEX_NAME "mutex_shm"

* oflag : O_CREAT Create and initialize it if not exist

* mode_t : file perssion -rw-r--r--

* value : 1

*/

if((sem_open(MUTEX_NAME,O_CREAT,0644,1)) < 0)

{

perror("sem_open");

exit(EXIT_FAILURE);

}

if((sem_open(FULL_NAME,O_CREAT,0644,0)) < 0){

perror("sem_open");

exit(EXIT_FAILURE);

}

}

/*

* close and unlink semaphore that we crated

*/

void SemDestroy()

{

sem_t * mutexPtr = sem_open(MUTEX_NAME,O_CREAT);

sem_t * fullPtr= sem_open(FULL_NAME,O_CREAT);

/* Destroy mutex */

sem_close(mutexPtr); // int sem_close(sem_t *sem);

sem_unlink(MUTEX_NAME); // int sem_unlink(const char *name);

/* Destory full*/

sem_close(fullPtr);

sem_unlink(FULL_NAME);

}

void P(sem_t *semPtr)

{

sem_wait(semPtr); //int sem_wait(sem_t *sem);

}

void V(sem_t *semPtr)

{

sem_post(semPtr); //int sem_post(sem_t *sem);

}

4-4 sender.c (传送消息到内存区域)

#include "common.h"

//key

key_t key;

//shared memory

int shmid;

char * shmptr;

char input[SHM_SIZE];

//semaphore

sem_t * full;

sem_t * mutex;

//semaphore

void Init()

{

key = KEY_NUM; //init key

shmid = GetShmId(key); // init shared memory

shmptr = shmat(shmid,NULL,0); // attach segement to vitural ...?

//semaphore init

full = sem_open(FULL_NAME,O_CREAT);

mutex = sem_open(MUTEX_NAME,O_CREAT);

}

void SaveMessage()

{

P(mutex);

strcpy(shmptr,input);

V(mutex);

V(full);

}

int main(int argc, char const *argv[])

{

Init();

/*waiting for user to input message*/

scanf("%s",input); //input message from shell

// TODO input a whole line

SaveMessage();

printf("Sender: Process End\n");

return 0;

}

4-5 receiver.c(从内存获取消息)

#include "common.h"

//key

key_t key;

//shared memory

int shmid;

char * shmptr;

char result[SHM_SIZE];

//semaphore

sem_t * full;

sem_t * mutex;

//semaphore

void Init()

{

key = KEY_NUM; //init key

shmid = GetShmId(key); // init shared memory

shmptr = shmat(shmid,NULL,0); // attach segement to vitural ...?

//semaphore init

full = sem_open(FULL_NAME,O_CREAT);

mutex = sem_open(MUTEX_NAME,O_CREAT);

}

void ReadMessage()

{

P(full);

P(mutex);

strcpy(result,shmptr);

V(mutex);

}

int main(int argc, char const *argv[])

{

Init();

/*waiting for user to input message*/

ReadMessage();

printf("Receiver : message is %s\n",result);

SemDestroy();

printf("Receiver : Process End \n");

return 0;

}

4-6 init.c(初始化)

#include "common.h"

int main(int argc, char const *argv[])

{

key_t key;

int semid; //semaphore id

int shmid; //shared memory id

/* Create key*/

key = KEY_NUM;

/* Initialize Semaphore*/

SemInit();

/* TODO Initialize Shared Memory*/

GetShmId(key);

printf("End of initialize\n");

return 0;

}

4-7 编译测试

make

c模拟linux进程管理课程设计,操作系统课程设计(三):Linux进程管理相关推荐

  1. 操作系统实验报告linux进程管理,计算机操作系统实验报告三Linux进程基本管理.doc...

    GDOU-B-11-112广东海洋大学学生实验报告书(学生用表) GDOU-B-11-112 实验名称 Linux进程基本管理 课程名称 计算机操作系统 课程号 学院(系) 专业 统 班级 学生姓名 ...

  2. 【操作系统精髓与设计原理】第三章-进程描述和控制

    3.1 什么是进程 进程是正在执行的程序. 进程也可以描述为:由一组元素组成的实体.进程的组成元素:程序代码,代码相关联的数据集和进程控制块. 标识符:进程唯一ID. 状态:运行,阻塞,就绪. 优先级 ...

  3. 现代操作系统:第三章 内存管理

    操作系统的工作是将这个存储体系抽象成为一个有用的模型并将管理这个抽象模型 操作系统中管理分层存储体系的部分称为存储管理器.它的任务是有效的管理内存,即记录哪些内存是正在使用的,哪些内存是空闲的,在进程 ...

  4. 操作系统:第三章 内存管理2 - 详解虚拟内存,页面置换算法,页面分配策略

    本文已收录至 Github(MD-Notes),若博客中有图片打不开,可以来我的 Github 仓库:https://github.com/HanquanHq/MD-Notes,涵盖了互联网大厂面试必 ...

  5. qnx linux和安卓,车载电子操作系统:QNX与Linux未来有望两家独大

    车载电子操作系统是汽车智能化的核心,能够有效分配车机的硬件资源,对车内各种任务功能进行协同管理,并控制各项任务优先级别.常见的车载电子操作系统有:QNX.Linux(Android,AaliOS).W ...

  6. 【Linux命令行与Shell脚本编程】三,Linux文件系统

    Linux命令行与Shell脚本编程 第三章 Linux文件系统 文章目录 Linux命令行与Shell脚本编程 三.Linux文件系统 3.1,查看文件 3.1.1,ls 命令 选项和参数 3.1. ...

  7. 操作系统笔记(三)进程管理之管理

    调度 context switch: save context(PCB), restore context(PCB). 开销 如何维护各个进程的状态:PCB + 队列(job队列,ready 队列,I ...

  8. 操作系统课程设计.doc 高分大作业(97分),共25页word版本

    操作系统课程设计 操作系统课程设计.doc 实验列表 实验内容 文档部分截图 关于实验过程截图 文档获取 操作系统课程设计.doc 操作系统课程设计高分大作业(97分),共25页word版本. wor ...

  9. 大学操作系统课程笔记

    第一章 操作系统引论 1.什么是操作系统? 操作系统(Operating System,OS)是指控制和管理整个计算机系统的硬件和软件资源,并合理地组织调度计算机的工作和资源的分配,以提供给用户和其他 ...

最新文章

  1. 2022-2028年中国TCO导电玻璃行业市场研究分析及前瞻规划报告
  2. pmdk -- libpmemlog 介绍
  3. 求e的近似值java_7-78 求e的近似值 (15 分)
  4. “一束光”让机器人也能拥有触觉?之江实验室这项技术惊艳世界
  5. k8s minikube启动时指定镜像源的启动方式
  6. C++与java的不同点
  7. 深入理解Async/Await
  8. RabbitMq(十七)rabbitmq的四种集群监控
  9. leetcode 53 python 动态规划
  10. SQLmap常用命令/使用教程
  11. vue 官方推荐的好用的三方库
  12. boder-radius属性
  13. mysql学习笔记 51_mysql学习笔记
  14. 自玩树莓派记录-关于树莓派LCD3.5英寸屏幕使用及raspios(raspbian)-lite简单GUI服务搭建记录
  15. 20、随机图片验证码API接口,免费好用
  16. vue适配PC端屏幕自适应
  17. 计算机硬件系统和操作系统
  18. 交换机的端口种类access、trunk、hybrid
  19. 再见了 Docker!K8S 云原生架构已成气候!
  20. 中国古诗文Python爬虫JJJ

热门文章

  1. 【JAVA笔记——道】Hibernate 线程本地化基础篇
  2. error: Program received signal SIGSEGV, Segmentation fault. (Codeblocks, C++)(2)
  3. 大数据在智慧城市中重要的作用
  4. 小程序中里的bindinput_云开发实战分享|诗和远方:旅行小账本云开发
  5. scrapy 中爬取时被重定向_Scrapy详解之scrapy shell
  6. python执行js脚本安全吗_手把手教你如何使用Python执行js代码
  7. php macro,如何利用 macro 方法来扩展 Laravel 的基础类的功能
  8. AcWing 1913. 公平摄影(前缀和+STL)
  9. springboot update数据_SpringBoot整合Mybatis+Druid+数据库(注解版)
  10. tomcat并发优化