Operating system experiment report process management and process communication

1, Experimental purpose

1. Master the concept of process and clarify the meaning of process.
2. Know and understand the essence of concurrent execution of processes, the process of blocking and waking up, and the process of termination and exit.
3. Familiar with process control methods such as sleep, synchronization and undo.
4. Analyze the phenomenon that processes compete for resources, and learn the methods to solve the mutual exclusion of processes.
5. Understand what is a signal, use the semaphore mechanism, and be familiar with the basic principle of inter process soft interrupt communication,
6. Familiar with the mechanism of message transmission and shared storage mechanism.

2, Experimental environment

Ubuntu 20.10, gcc compiler

3, Experimental content

  1. Write a program that uses the system call fork() to create two sub processes. When this program runs, a parent process and two child processes execute concurrently in the system. Observe the experimental results and analyze the reasons.

  2. Create a process with fork(), then call exec(), replace the content of the sub process with a new program, use wait() to control the execution sequence of the process, master the process control methods such as sleep, synchronization and revocation of the process, and analyze the causes according to the experimental results.

  3. Write a multi process concurrent program, lock each process with lockf() to realize mutual exclusion between processes, observe and analyze the phenomena and causes.

  4. Write the program: use fork() to create two sub processes, and then use the system call signal() to let the parent process capture the interrupt signal on the keyboard (that is, press the ^ c key); After capturing the interrupt signal, the parent process sends a signal to the two child processes with the system call kill(). After capturing the signal, the child processes respectively output the following information and terminate:
    Child process1 is killed by parent!
    Child process2 is killed by parent!
    After the parent process waits for the two child processes to terminate, it outputs the following information and terminates:
    Parent process is killed!
    The mechanism of process synchronization using soft interrupt communication in semaphore mechanism is analyzed.

  5. Using the system calls msgget (), msgsnd (), msgrev (), and msgctl(), a 1k message sending and receiving program is compiled, and the message creation, sending and receiving mechanism and control principle are analyzed.

  6. A 1k long program for sending and receiving shared storage area is compiled, and measures for mutually exclusive access and process synchronization of the shared storage area are designed to ensure correct communication.

4, Experimental principle, system call functions used in the experiment (including those introduced in the experimental principle and used by myself), and experimental steps

Experimental principle:

slightly

Experimental steps:

Question 1:

Because the title says to create two child processes, and according to the return value of the fork() function, it can be found that if the return value = = 0 indicates that it is currently a child process, and the return value > 0 indicates that it is currently a parent process. According to this, the program can be separated into two different processes through the if else statement!

Question 2:

At the very beginning, the way to create the same process as the first question is to use execl() instead of the following in the sub process.

It also calls wait() in the parent process to ensure that the parent process does not end ahead of time.

Question 3:

First create two sub processes, then lock them first, output 10 numbers through the for loop, and unlock them after execution:

Question 4:

First create two sub processes, and then receive signals in the process. Later, use the pause() function to pause the program until the signal is received. After receiving the termination signal, send a signal to the child process.

After receiving the signal, the subprocess terminates the operation of the program.

The parent process finally calls wait() to ensure that the parent process ends in the end.

Question 5:

First, create two processes in the main function:
server() is called in the parent process, and the message is received.
Call client() in the child process and send the message.

Send message in client() function:

Send message in server() function:
First call the wait() function and wait for the client to send the message and end the process before receiving the message.

Question 6:

In the main() function, create a child process to execute the server, and the parent process to execute the client

Send message in client

Message received in server:

Once the server receives a message, it will set addr to - 1 to wait for the client to send the message again.

5, Analysis of experimental results (screen capture of experimental results, experimental analysis corresponding to experimental results)

1. The corresponding analysis of experimental results and experimental procedures, experimental steps, experimental principle and operating system principle;
2. The problems and reasons of the reaction of experimental results under different conditions;
3. The experimental results show the performance analysis of the algorithm, such as time, efficiency and robustness.

Question 1:

In the case of multi-core CPU, through the experimental results, it can be found that the output order of "parent process", "child process 1" and "child process 2" is different when the program is executed many times. It shows that the execution order of the three processes is uncertain, which depends on the scheduling timing of the process.
Then adjust the CPU to core 1 and restart,


It can be found that in the case of a single core, the execution order is relatively fixed. The parent process is executed first and then the two child processes are executed. Because the single core CPU can only execute one hop instructions when processing multithreaded programs, and each process executes in turn, the single core CPU controls the randomness of the experimental results to a certain extent.

Question 2:


Executing the program, you can find that the program has output all the files in the current folder.

Question 3:


It can be found that after each process is locked, it will not switch to the other two processes for execution. Only after the process is unlocked after execution, it will switch to the next process for execution.

Question 4:

Running program:

Start a new terminal, execute kill -2 54969, and send an interrupt signal to the parent process:

The final operation results are as follows:

Question 5:
The information sent by cilent has been successfully received and displayed in the server.

Question 6:
Every time a client sends a message, the server will receive it, and then the client will send the next message.

6, Experimental summary

Each problem started after I found some information on the Internet. It took me a long time and encountered many difficulties. For example, I encountered many unsuitable places when operating in linux system, and I spent a lot of time searching for information to solve many places I didn't understand. But I also gained a lot. Through this experiment, I also had a better understanding of the process, messages and shared areas.

7, Experimental data and source code (students must submit their own designed program source code with comments, and the electronic version of the source code shall also be submitted), including the program of thinking questions.

First question

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

int main()
{
	int p;
	p = fork();
	if (p < 0)
	{
		//The return value of fork() function < 0 indicates that the process creation failed!
		printf("Sub process creation failed!\n");
	}
	else if (p == 0)
	{
		//p==0 indicates that this is a child process
		printf("I'm the first child process. The number is%d\n", getpid());
		exit(0); //Interrupt process
	}
	else
	{
		//p> 0 indicates that it is currently the parent process
		//Create second child process
		int q;
		q = fork();
		if (q < 0)
		{
			printf("Sub process creation failed!\n");
		}
		else if (q == 0)
		{
			printf("I'm the second child process. The number is%d\n", getpid());
			exit(0);
		}
		else
		{
			printf("I'm the parent process. The number is%d\n", getpid());
			exit(0); //Interrupt process
		}
	}
}

Second question

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
int main()
{
	int p;
	p = fork(); //Create child process
	switch (p)
	{
	case -1:
		printf("Creation failed\n");
		exit(1);
	case 0: //Subprocess
		execl("/bin/ls", "ls", NULL);
		printf("execfail!\n");
		exit(1);
	default:		//Parent process
		wait(NULL); //Pause the parent process first to avoid early termination of the parent process!
		printf("lscompleted!\n");
		exit(0);
	}
}

Question 3

#include <stdio.h>
#include <unistd.h>
int main()
{
    int p;
    int i;
    p = fork(); //Create child process
    if(p < 0){
        printf("The first child process creation failed\n");
    }else if(p == 0){
        //Is currently a child process
        lockf(1,1,0);   //Lock
        for(i = 0;i <10;++i){
            printf("%d\n",i);
        }
        printf("The execution of the first sub process is completed\n");
        lockf(1,0,0);   //Unlock
    }else{
        p = fork();  //Create second child process
        if(p < 0){
            printf("The second child process creation failed\n");
        }else if(p == 0){
            //Subprocess
            lockf(1,1,0);   //Lock
            for(i = 10;i <20;++i){
                printf("%d\n",i);
            }
            printf("The execution of the second sub process is completed\n");
            lockf(1,0,0);   //Unlock
        }else{
            //Is currently the parent process
            lockf(1,1,0);   //Lock
            for(i = 20;i <30;++i){
                printf("%d\n",i);
            }
            printf("Parent process execution completed\n");
            lockf(1,0,0);   //Unlock
        }
    }
}

Question 4

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

void sighandler(int sig){
    //printf("Response\n");
}

int main(){

    int pid1;
    int pid2;
    pid1 = fork(); //Create the first child process
    if(pid1 == 0){
        //First child process
        printf("I'm the first child process, pid=%d\n",getpid());
        signal(SIGUSR1,sighandler);   //Receive signal
        pause();   //The program pauses until the signal appears
        printf("Child process1 is killed by parent!\n");  
        exit(1);
    }else{
        pid2 = fork(); //Create second child process
        if(pid2 == 0){
            // Second child process
            printf("I'm the second child process, pid=%d\n",getpid());
            signal(SIGUSR2,sighandler);   //Receive signal
            pause();   //The program pauses until the signal appears
            printf("Child process2 is killed by parent!\n");
            exit(2);
        }else{
            //Parent process
            printf("I'm the parent process, pid=%d\n",getpid());
            signal(SIGINT,sighandler);
            pause();
            kill(pid1,SIGUSR1); //Send user defined signal 1 to process pid1
            kill(pid2,SIGUSR2); //Send user defined signal 2 to process pid2
            wait(NULL);
            wait(NULL);
            wait(NULL);         //Wait for two child processes
            printf("Parent process is killed!\n");
            exit(0);
        }
    }
}

Question 5

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

#define MSGKEY 1024 / / message key

typedef struct msgForm{ //Message structure
    long  mtype;            /*Message type*/
    char  mtext[1024];      /*Text of the message*/
}msgForm;

int msgqid;

void client(){
    msgForm msg;
    msg.mtype = 10; //Define message type
    strcpy(msg.mtext,"Hello,World!!!");
    msgqid = msgget(MSGKEY,0777); //Create message queue
    msgsnd(msgqid,&msg,sizeof(msg),0);
    printf("(client)Message sent!\n");
    printf("(client)The message sent is%s\n",msg.mtext);
    exit(0);
}

void server(){
    msgForm msg;
    msgqid=msgget(MSGKEY,0777|IPC_CREAT); //Create a queue that all users can read, write, and execute
    wait(0);    //Ensure that cilent sends the message and ends the process before continuing with the following
    msgrcv(msgqid,&msg,sizeof(msg),0,0);    //Receive information
    printf("(server)Information accepted!\n");
    printf("(server)The received information is%s\n",msg.mtext);
    msgctl(msgqid, IPC_RMID,0); //Identifier of the elimination message queue.
    exit(0);
}


int main(){
    int p;
    p = fork(); //Create child process
    if(p == 0){
        client();
    }else{
        server();
    }
    return 0;
}

Question 6

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

#define SHMKEY 1024 / / key of shared memory
int shmid, i;
int *addr;

void client()
{
    int i;
    shmid = shmget(SHMKEY, 1024, 0777 | IPC_CREAT); /*Create a shared storage area with a name of 75 and a size of 1024 bytes. Do not create it repeatedly*/
    addr = shmat(shmid, 0, 0);                      /*The virtual address (first address) of the process to which the shared store is attached*/
    for (i = 9; i >= 0; i--)
    {
        while (*addr != -1); //Ensure that the server receives a message and sends the next one
        printf("(client)sent\n");
        *addr = i;
    }
    exit(0);
}

void server()
{
    shmid = shmget(SHMKEY, 1024, 0777 | IPC_CREAT); //Create a shared storage area with a size of 1024 bytes
    addr = shmat(shmid, 0, 0);                      //The virtual address (first address) of the process to which the shared store is attached
    do
    {
        *addr = -1;
        while (*addr == -1);//Response client
        printf("(server)received\n");
    } while (*addr);
    shmctl(shmid, IPC_RMID, 0); //Undo shared storage and return resources
    exit(0);
}

void main()
{
    int p;
    p = fork(); //Create child process
    if(p < 0){
        printf("Sub process creation failed!\n");
    }
    else if(p == 0){
        server();
    }else{
        client();
    }

}

8, Thinking questions

1. Process creation and process concurrent execution

(1) How does the system create processes?
Answer: after the fork() system call, perform the following operations:
① Apply for a blank PCB (process control block).
② Allocate resources for the new operation.
③ Initialize PCB.
④ Insert the new process into the ready queue.

(2) When the newly created process is called for the first time, where is its entry?
A: the process control block (PCB) structure of a process has a pointer to its TTS (task status segment), which stores the process entry.

(3) Using strace and ltrace - F - I - S/ Executable file name view the program execution process, analyze the causes, and draw the process family tree.

The execution process is as shown in the figure. The parent process first creates the child process 2, then creates the child process 1, and is killed after outputting the content. The process family tree is shown in the figure below:

2. Process control such as sleep, synchronization and revocation of processes

(1) What happens when the executable is loaded?
A: the process loads the command ls with exec(). After exec(), the code of the sub process is replaced by the code of ls. At this time, the PC of the sub process points to the first statement of ls and starts executing the command code of ls.

(2) What is process synchronization? How does wait() synchronize processes?
A: process synchronization means that in a multiprogramming environment, processes are executed concurrently, and there are different mutual constraints between different processes. As soon as the wait() function is called, the parent process will suspend execution until a process ends.

(3) How do wait() and exit () control the randomness of experimental results?
A: after using the execl() function, the child process lists all the files in the current directory. After executing this function, it calls exit() to exit the current process and then continues to execute the parent process. Therefore, we can find the lscompleted of the parent process! Always output at the end, which controls the randomness of the experimental results.

3. Multiple processes run concurrently through locking and mutual exclusion

(1) Are the output results of process locking and unlocking the same? Why?
A: different. Because after the process is locked, it ensures that when one of the processes is executed, it will not switch to the other two processes for execution. It will only switch to the other two processes after unlocking. If the process is unlocked, the program will switch to another two processes at any time, and the output results will be different.

4. Soft interrupt communication between processes is realized by signal mechanism

(1) In order to get the results required by the experimental content, which system call functions need to be used to realize the communication control and synchronization between processes?
A: kill() and signal()

(2) What are the functions of kill() and signal() in signal communication? What happens if you comment them out separately?
Answer:

  • The kill() function is used to send signals to the specified child process, and the signal() function is used to receive the specified signals. The signal() function needs to be used together with the pause() function.
  • If kill() is commented out, the child process will not receive the signal, causing the child process to wait for the signal to appear, the parent process to wait for the child process to end, and finally the program will be blocked.
  • If signal() is commented out, the parent process cannot receive the interrupt signal, the program does not respond after the interrupt signal is sent, and the program is blocked all the time.

5. Sending and receiving of messages

(1) In order to facilitate the operation and observation of results, several programs need to be compiled for message sending and receiving?
A: there are two programs, in which the client sends messages and the server receives messages.

(2) How do these programs edit, compile, and execute? Why?
Answer:
① The two programs edit and execute GCC client C - O client and GCC server c -o server
② Execution:/ server and/ client
③ client and server are two different programs that need to be edited, compiled and executed separately. client sends requests and server receives messages.

(3) How to synchronize the sending and receiving of messages?
A: both sending and receiving programs must always be ready to communicate with each other.

6. Shared store communication for processes

(1) In order to facilitate the operation and observation of the results, how to reasonably design the program to realize the shared memory communication between sub processes?
A: each process needs to open up a shared storage area and attach it to its own memory space, so that it can read and write normally.

(2) Compare the performance, advantages and disadvantages of message communication and shared memory communication.
Answer:
① The establishment of message queue consumes less resources than the establishment of shared area. The former is only a software setting problem, and the latter needs to operate the hardware and realize the memory image. Of course, the control is more complex than the former. If the queue or share is re established every time, the establishment of the shared area has no advantage.
② When the message queue and the shared area are established, the data transmission in the shared area is supported by the system hardware and does not consume redundant resources; Message passing, controlled and implemented by software, needs to consume certain cpu resources. In this sense, shared area is more suitable for frequent and large amount of data transmission.
③ The delivery of messages is controlled by synchronization. When waiting for the message, the process goes to sleep and no longer consumes cpu resources. If the shared queue does not synchronize with other mechanisms, the party receiving the data must query constantly, which wastes a lot of cpu resources in vain. It can be seen that the use of message mode is more flexible.

Added by BigJohn on Wed, 19 Jan 2022 06:25:30 +0200