Operating system experiment

Keywords: Linux Operating System

Experiment 1 command interpreter

Experimental content

Write a micro command interpreter minishell.c in C language, which can receive and interpret the following commands:
(1) dir lists the current directory
(2) cop file1 file2 copy files
(3) era filename delete file
(4) disp string display string
(5) end end, exit
requirement:
(1) Check the validity of the command. If there is an error, display the error message and wait for re-entry;
(2) A space before and after the command indicates a legal command.

Experimental preparation

  • gets() reads the string until the end of carriage return, but does not include carriage return
  • strcspn(str1,str2) returns a string beginning with str1 that does not contain str2
  • strncpy(str1,str2,n) copies the first n str2 strings into str1
  • strcmp(str1,str2) compares str1 and str2
    • Return value is less than 0, STR1 < STR2
    • Equal to zero str1 == str2
    • Greater than zero STR1 > STR2
  • system(command) execute command

Sample program

#define true 1
#define false 0

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(){
    char cmdl[80];
    char *scwt[] = {"exit","dir","time"};
    static int cmdnum = 3;  // Number of commands available
    char cmd[80];
    int j,n;

    while(true){
        printf("Please input command:");
        gets(cmdl); // Take command line input
        n = strcspn(cmdl," ");// Fetch command part
        if(n > 0 || strlen(cmdl) > 0){
            strncpy(cmd,cmdl,n);
            // Composition string
            cmd[n] = '\0';
            for(j = 0;j < cmdnum;j++){
                if(strcmp(cmdl,scwt[j]) == 0) break;
            }
            if(j == 0) exit(0);
            if(j < cmdnum){
                system(cmdl);
                continue;
            }
            printf("Bad command!\n");
        }
    }
}

Experimental code

Don't let it out for the time being

Experiment 2 process management

Experimental content
1. Process creation
Write a program that uses the system call fork() to create two sub processes. Let the Parent process display the string 'Parent:'; The two subprocesses display the strings' Child1: 'and' Child2: 'respectively. Run this program several times, observe the results displayed on the screen, and analyze the causes.
2. Process control
Modify the written program, output a sentence repeated many times, observe the results displayed on the screen when the program is executed, and analyze the reasons.
If the system call lockf() is used to lock each process in the program, the mutual exclusion between processes can be realized, the results displayed on the screen can be observed, and the causes can be analyzed.

Experimental preparation content and sample program

fork test

Function description of fork:

  • fork() creates a new process by copying the process. A child process is similar to a copy of the current process, but:
    • The child process has its own unique process ID, and the PID of this process is different from that of any process
    • The parent process ID of the child process is equal to the process ID of the parent process
  • Return value:
    • If successful, return the PID of the child process in the parent process and 0 in the child process
    • Failed, returned - 1 in the parent process, no child process was created
crescent_p@CP:~/Program/Experiment2$ gcc -o fork1 forkTest1.c 
crescent_p@CP:~/Program/Experiment2$ ./fork1 
fork test
fork test
#include <stdio.h>
#include <unistd.h>

int main(){
	fork();
	printf("fork test\n");
	return  0;
}

Analysis: why is it output twice?

  • A process is created at the beginning of the program
  • When the process fork s, a child process is created
    • The code of the child process is a copy of the code of the parent process
    • The code execution progress of the child process is consistent with that of the parent process when creating the child process

Test 2:

#include <stdio.h>
#include <unistd.h>

int main(){
	pid_t pid;
	pid = fork();
	// Parent process
	if(pid > 0){
		printf("I am father\n");
	}
	if(pid == 0){
		printf("I an son\n");
	}
	if(pid < 0){
		printf("fork error\n");
	}
	printf("main over\n");
	return 0;
}

Why the analysis results are different:

  • Why is there son and father again?
    • In the parent process, fork() returns the PID of the child process, which is greater than 0, so the first if will be executed
    • In the child process, fork() returns the PID of the child process, equal to 0, so the second if will be executed
  • Why does the result of executing this executable file twice differ?
    • For the asynchrony of processes, we set the parent process as p1 and the child process as p2
    • First execution:
      • After p1 executes the first if, it is p2's turn to run the processor
    • Second execution:
      • After p1 is executed, it is p2's turn to the processor

Test 3:

#include <stdio.h>
#include <unistd.h>

int main(){
	printf("Execute to fork Function whose process was %d,Its parent process is %d\n",getpid(),getppid());
	sleep(1);
	fork();
	printf("This process id by:%d,Its parent process is%d\n",getpid(),getppid());
	return 0;
}


Test 4:

#include <stdio.h>
#include <unistd.h>
int main(){
	pid_t p1,p2;
	while((p1 = fork()) == -1);
	// Subprocess
	if(p1 == 0) { 
		puts("b");
	}
	else {
		puts("a");
	}
	return 0;
}

Experimental code

Don't let it out for the time being


Experiment 3 communication between processes

pipeline communication

Experimental preparation content and sample program

Test pipe():

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>


int main(){
    pid_t pid;
    int fd[2];
    char buf[50],s[50];
    // Created pipe, half duplex
    pipe(fd);
    while((pid = fork()) == -1);
    // Subprocess
    if(pid == 0){
        sprintf(buf,"Child is sending message!");
        // fd[1] write pipeline
        write(fd[1],buf,50);
        // exit also writes the contents of the file buffer back to the file before exiting
        // Exiting the process is actually a zombie process
        exit(0);
    }else{
        // Once a process calls wait, it blocks itself immediately
        // wait automatically analyzes whether a child process of the current process has exited
        // If it finds such a sub process that has become a zombie
        // wait will collect the information of the child process, destroy it completely and return
        // If such a child process is not found, the wait will block here until one appears.
        wait(0);
        // fd[0] reads the pipeline and reads the contents of the pipeline into s
        read(fd[0],s,50);
        printf("%s\n",s);
        exit(0);
    }
    return 0;
}

A pipe

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <string.h>

int main(){
    // Channel array
    int fd[2];
    pid_t pid;
    // Be sure to create the pipeline first, otherwise the child process out of fork will also create the key pipeline
    pipe(fd);
    while((pid = fork()) == -1);
    // Subprocess
    if(pid == 0){
        char str[100] = {0};
        printf("child process: input string:\n");
        scanf("%s",str);
        // Write to pipe
        write(fd[1],str,strlen(str));
        exit(0);
    // Parent process
    }else{
        wait(0);
        char buf[30] = {0};
        // Read from pipe to buf
        read(fd[0],buf,30);
        printf("parent process:\n %s\n",buf);
        exit(0);
    }
    return 0;
}

Dual channel:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <string.h>

int main(){
    // Two pipes
    int fd1[2],fd2[2];
    // Create two channels
    pipe(fd1),pipe(fd2);
    pid_t pid;
    while((pid = fork()) != -1);
    // Subprocess
    if(pid == 0){
        char read_buf1[100] = {0};
        char write_buf1[100] = {0};
        printf("child process write:\n")
        scanf("%s",write_buf1);
        // write in
        write(fd1[1],write_buf1,strlen(write_buf1));
        // dormancy
        sleep(10);
        // Read in
        read(fd2[0],read_buf1,100);
        printf("child process read:\n %s\n",read_buf1);
        exit(0);
    // Parent process
    }else{
        sleep(5);
        char read_buf2[100] = {0};
        char write_buf2[100] = {0};
        read(fd1[0],read_buf2,100);
        printf("parent process read:\n %s\n",read_buf2);

        printf("parent process write:\n")
        scanf("%s",write_buf2);
        // write in
        write(fd2[1],write_buf2,strlen(write_buf2));
        exit(0);
    }
    return 0;
}

Experimental code

Don't let it out for the time being

Shared memory

Experimental preparation content and sample program

#include<stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <string.h>
#include <unistd.h>

int main(){
    // Shared memory identifier
    int shmid;

    // Create shared memory
    if((shmid = shmget((key_t)0x5005,1024,0666|IPC_CREAT)) == -1){
        printf("shmat(0x5005) failed\n");
        return -1;
    }
    // Pointer to shared memory
    char *ptext = 0;

    // Connect the shared memory to the address space of the current process, and point to it by ptext
    ptext = (char *)shmat(shmid,0,0);

    // Operating the ptext pointer of this program is to operate the shared memory
    printf("Before writing:%s\n",ptext);
    sprintf(ptext,"The process number of this program is:%d",getpid());
    printf("After writing:%s\n",ptext);

    // Separates shared memory from the current process
    shmdt(shmid);

    // Delete shared memory
    if(shmctl(shmid,IPC_RMID,0) == -1){
        printf("shmctl(0x5005) failed\n");
        return -1;
    }
}

Experimental code

#include<stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <string.h>
#include <unistd.h>

int main(){
    // Shared memory identifier
    int shmid;

    // Create shared memory
    if((shmid = shmget((key_t)0x5005,1024,0666|IPC_CREAT)) == -1){
        printf("shmat(0x5005) failed\n");
        return -1;
    }
    // Pointer to shared memory
    char *ptext = 0;

    // Connect the shared memory to the address space of the current process, and point to it by ptext
    ptext = (char *)shmat(shmid,0,0);
    printf("Please enter the name of the contact\n");
    char name[50];
    scanf("%s",name);
    printf("Please enter the contact's phone number\n");
    long long tel;
    scanf("%lld",&tel);

    // Operating the ptext pointer of this program is to operate the shared memory
    // Send message to shared memory
    sprintf(ptext,"contacts: %s\t contact number: %lld\n",name,tel);
    // Read from shared memory
    printf("Read data from shared memory:\n%s\n",ptext);

    // Separates shared memory from the current process
    shmdt(ptext);

    // Delete shared memory
    if(shmctl(shmid,IPC_RMID,0) == -1){
        printf("shmctl(0x5005) failed\n");
        return -1;
     }
}

Message queue

Experimental preparation content and sample program

message.h

#ifndef MESSAGE_H
#define MESSAGE_H
struct mymsgbuf
{
    long mtype;
    char mtext[256];
};
#endif

msg_server.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#include "message.h"

int msqid = -1;

// Soft terminal
void sig_handle(int signo){
    if(msqid != -1) msgctl(msqid,IPC_RMID,NULL);    // delete
    printf("server quit...\n");
    exit(0);
}

int main(){
    struct mymsgbuf msgbuf;
    int left,right;
    char c;
    int length;

    if((msqid = msgget(999,0666)) != -1){
        msgctl(msqid,IPC_RMID,NULL);    // delete
    }

    if((msqid = msgget(999,IPC_CREAT|0666)) == -1 ){
        printf("error:getmsg\n");
        exit(1);
    }

    signal(SIGINT,sig_handle);      // Register soft interrupt
    for(;;){
        if(msgrcv(msqid,&msgbuf,256,1L,0) == -1){
            printf("error:msgrcv\n");
            exit(1);
        }
        length = strlen(msgbuf.mtext);
        left = 0;
        right = length - 1;
        while (left < right)
        {
            c = msgbuf.mtext[left];
            msgbuf.mtext[left] = msgbuf.mtext[right];
            msgbuf.mtext[right] = c;
            left++;
            right--;
        }
        msgbuf.mtext[length] = '\0';

        msgbuf.mtype = 2;   // Change type to 2
        if(msgsnd(msqid,&msgbuf,256,0) == -1){
            printf("error:msgsnd");
            exit(1);
        }
    }
    msgctl(msqid,IPC_RMID,NULL);
    exit(0);
}

msg_client.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#include "message.h"

int main(){
    struct mymsgbuf msgbuf;
    int msqid;

    if((msqid = msgget(999,0666)) == -1){
        printf("Server is not running\n");
        exit(1);
    }
    printf("Input a line:");
    scanf("%s",msgbuf.mtext);
    msgbuf.mtype = 1;

    if(msgsnd(msqid,&msgbuf,256,0)==-1){
        printf("error:msgsnd\n");
        exit(1);
    }
    if(msgrcv(msqid,&msgbuf,256,2L,0) == -1){
        printf("error:msgrcv\n");
        exit(1);
    }
    printf("The reversed line is :%s\n",msgbuf.mtext);
    exit(0);
}

msgsend.c

#include <stdio.h>
#include <sys/ipc.h>
#include <errno.h>
#include <unistd.h>
#include <sys/msg.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

// Message types, enumerating
enum MT{MI=1,MD,MS,MSTU,MEMP};
#define QUIT 0
#define MSG_MAX_LEN 1024
#define NAME_LEN 48

typedef struct Msg{
    int msgtype;            //Type of message
    char msg[MSG_MAX_LEN];  // Content of message
}Msg;

typedef struct Stu{
    int id;
    char name[NAME_LEN];
    int s[3];           // Three grades
}Stu;

typedef struct Emp
{
    int id;
    char name[NAME_LEN];
    float salary;
}Emp;



void menu(void){
    printf("***Message queue sending test interface***\n");
    printf("*** %d.int Type of data\n",MI);
    printf("*** %d.double Type of data\n",MD);
    printf("*** %d.character string\n",MS);
    printf("*** %d.Student information\n",MSTU);
    printf("*** %d.Employee information\n",MEMP);
    printf("*** %d.sign out\n",QUIT);
    printf(">>>");
}

size_t readInt(Msg *msg){
    // Sets the type of message
    msg->msgtype = MI;
    printf("input integer:");
    // Read the message into the msg attribute of the message structure
    scanf("%d",(int*)msg->msg);
    return sizeof(int);
}
size_t readDouble(Msg *msg){
    msg->msgtype = MD;
    printf("input double:");
    scanf("%lf",(double*)msg->msg);
    return sizeof(double);
}
size_t readString(Msg *msg){
    msg->msgtype = MS;
    printf("input string:");
    // Read wrap
    scanf("%*c");
    gets(msg->msg);     // gets is not safe
    // Add \ 0
    return strlen(msg->msg)+1;
}
size_t readStu(Msg *msg){
    msg->msgtype = MSTU;
    // Strong rotation
    Stu *pstu = (Stu*)msg->msg;
    printf("input stu's id:");
    scanf("%d",&pstu->id);
    printf("input stu's name:");
    scanf("%s",pstu->name);
    printf("input three score:");
    scanf("%d %d %d",&pstu->s[0],&pstu->s[1],&pstu->s[2]);
    return sizeof(Stu);
}
size_t readEmp(Msg *msg){
    msg->msgtype = MEMP;
    Emp *pe = (Emp*)msg->msg;
    printf("input emp's id:");
    scanf("%d",&pe->id);
    printf("input emp's name:");
    scanf("%s",pe->name);
    printf("input emp's salary:");
    scanf("%f",&pe->salary);
    return sizeof(Emp);
}


int main(){
    key_t keyid = ftok(".",250);
    if(keyid == -1){
        perror("ftok");
        return -1;
    }
    // Create message queue
    int msgid = msgget(keyid,IPC_CREAT|0666);
    if(msgid == -1){
        perror("msgget");
        return -1;
    }
    // Create message
    Msg msg = {};
    bool run = true;
    size_t msgsz = 0;
    while(run){
        menu();
        int opt = 0;
        scanf("%d",&opt);
        switch (opt)
        {
        case MI:msgsz = readInt(&msg);break;
        case MD:msgsz = readDouble(&msg);break;
        case MS:msgsz = readString(&msg);break;
        case MSTU:msgsz = readStu(&msg);break;
        case MEMP:msgsz = readEmp(&msg);break;
        case QUIT:run = false;break;
        default:
            printf("error operation!\n");
        }
        // msgsz is the length of the message, excluding the length of the message type
        int ret = msgsnd(msgid,&msg,msgsz,0);   //0: blocking IPC_NOWAIT is not blocked
        if(ret == -1){
            perror("msgend");
            run = false;
        }
    }

    return 0;
}

msgrecive.c

#include <stdio.h>
#include <sys/ipc.h>
#include <errno.h>
#include <unistd.h>
#include <sys/msg.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

// Message types, enumerating
enum MT{MI=1,MD,MS,MSTU,MEMP,FIRST,ABSL};
#define QUIT 0
#define MSG_MAX_LEN 1024
#define NAME_LEN 48

typedef struct Msg{
    int msgtype;            //Type of message
    char msg[MSG_MAX_LEN];  // Content of message
}Msg;

typedef struct Stu{
    int id;
    char name[NAME_LEN];
    int s[3];           // Three grades
}Stu;

typedef struct Emp
{
    int id;
    char name[NAME_LEN];
    float salary;
}Emp;



void menu(void){
    printf("***Message queue acceptance test interface***\n");
    printf("*** %d.int Type of data\n",MI);
    printf("*** %d.double Type of data\n",MD);
    printf("*** %d.character string\n",MS);
    printf("*** %d.Student information\n",MSTU);
    printf("*** %d.Employee information\n",MEMP);
    printf("*** %d.Accept the first message \n",FIRST);
    printf("*** %d.Accepts messages whose specified message is less than the minimum absolute value \n",ABSL);
    printf("*** %d.sign out\n",QUIT);
    printf(">>>");
}


void showMsg(Msg *msg){
    switch (msg->msgtype)
    {
        case MI:printf("recv:%d\n",*(int*)msg->msg);break;
        case MD:printf("recv:%f\n",*(double*)msg->msg);break;
        case MS:printf("recv:%s\n",msg->msg);break;
        case MSTU:{
            Stu *ps = (Stu *)msg->msg;
            printf("recv:%d %s %d %d %d\n",ps->id,ps->name,ps->s[0],ps->s[1],ps->s[2]);
            break;
        }
        case MEMP:{
            Emp *pe = (Emp *)msg->msg;
            printf("recv:%d %s %f\n",pe->id,pe->name,pe->salary);
            break;
        }
    }
}

int main(){
    key_t keyid = ftok(".",250);
    if(keyid == -1){
        perror("ftok");
        return -1;
    }
    // Create message queue
    int msgid = msgget(keyid,IPC_CREAT|0666);
    if(msgid == -1){
        perror("msgget");
        return -1;
    }
    // Create message
    Msg msg = {};
    bool run = true;
    size_t msgsz = 0;
    // Type of message read
    int msgtype = 0;
    while(run){
        menu();
        int opt = 0;
        scanf("%d",&opt);
        if(opt >= MI && opt <=MEMP){
            msgtype = opt;
        }else if(opt == FIRST){
            msgtype = 0;
        }else if(opt == ABSL){
            printf("input masgtype(<0):");
            scanf("%d",&msgtype);
            if(msgtype > 0) msgtype *= -1;
        }else if(opt == 0){
            run = false;
            break;
        }
        int ret = msgrcv(msgid,&msg,MSG_MAX_LEN-1,msgtype,IPC_NOWAIT);   
        if(ret == -1){
            if(errno == EAGAIN){
                printf("no this type message");
            }else{
                perror("msgend");
                run = false;
            }
            
        }else{
            // Display message content
            showMsg(&msg);
        }
        
    }
    return 0;
}

Experimental code

Don't let it out for the time being

Posted by jazz_snob on Mon, 04 Oct 2021 15:00:33 -0700