Operating system experiment 2: process communication (pipes and shared memory)

Experiment 2: Process Communication (1) - Pipes and Shared Memory

1. The purpose of the experiment

1. Familiar with and master the pipeline mechanism and realize inter-process communication
2. Familiar with and master the shared memory mechanism and realize inter-process communication

2. Experiment content and steps

1. Task 1
(1) Read the above example of communication between parent and child processes using pipes (Example 1), write out the running result of the program and analyze it.
(2) Write a program: The parent process uses a pipe to hand over a string to the child process for processing. The child process reads the string, reverses the characters in it and then hands it to the parent process, and the parent process finally reads and prints the reversed string.
2. Task 2
(1) Read the program in Example 2, run the program once, and then use the ipcs command to check the status of the shared memory in the system, execute the program again, and then use the ipcs command to check the status of the shared memory in the system. Compare the results and analyze the reasons. Finally, use the ipcrm command to delete the shared storage area created by yourself.
(2) Each student logs in to two windows, first run example 3 program 1 in one window (or only log in to one window, first run program 1 in the background mode in this window), and then run example 3 in another window Program 2, observe and analyze the running results of the program. After running, you can use ctrl+c to end the running of program 1.
(3) Write a program: use the system calls shmget(), shmat(), shmdt(), shmctl() to program. Requires that a 30-byte long private shared memory segment be generated in the parent process. Next, set a character pointer to the shared memory segment, and write a string of uppercase letters to the memory area pointed to by the pointer. Call fork() to spawn a child process and let the child process display the contents of the shared memory segment. Next, the uppercase letters are changed to lowercase, and the child process modifies the contents of the shared memory. After that, the child process will detach the shared memory segment and exit. After the parent process sleeps for 5 seconds, the content of the shared memory segment is displayed here (it is already lowercase at this time). -

3. Analysis of code and running results

1. Task 1

Example 1:

#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include <sys/wait.h>
int main()
{
    
       int x,fd[2];
    char buf[30],s[30];
    pipe(fd);
    while ((x=fork())==-1);
    if (x==0)
    {
    
    
       close(fd[0]);
       printf("Child Process!\n");
       strcpy(buf,"This is an example\n");
       write(fd[1],buf,30);
       exit(0);
    }
    else{
    
    
       close(fd[1]);
       printf("Parent Process!\n");
       read(fd[0],s,30);
       printf("%s\n",s);
   }
   return 0;
}

(1) Read the above example of communication between parent and child processes using pipes (Example 1), write and analyze the running results of the program.
operation result:
insert image description here

Analysis:
Use the system call pipe() to create a simple pipe. fd[0] stores the file descriptor (pipe exit) used by the reading process, and fd[1] stores the file descriptor (pipe entry) used by the writing process. First run the parent process, then close the parent process, the child process starts, sends a message to the parent process, then closes the child process, the parent process receives the message and prints the output.
(2) Write a program: The parent process uses a pipe to hand over a string to the child process for processing. The child process reads the string, reverses the characters in it and then hands it to the parent process, and the parent process finally reads and prints the reversed string.
Write the program as follows:

#include<stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
int main(){
    
    
        int x,count,left,right,temp,fd[2],fe[2];
        char c,buf[30],s[30];
        pipe(fd);
        pipe(fe);
        printf("please input a line of char:\n");
        scanf("%s",buf);
        while((x=fork())==-1);
        if(x==0){
    
    
                close(fd[0]);
                close(fe[1]);
                printf("Child Process!\n");
                write(fd[1],buf,30);
                read(fe[0],buf,30);
                printf("%s\n",buf);
                exit(0);
        }else{
    
    
                close(fd[1]);
                close(fe[0]);
                count=0;
                do{
    
    
                        read(fd[0],&c,1);
                        s[count++]=c;
                }while(c!='\0');
                printf("Parent Process!\n");
                printf("%s\n",s);count-=2;
                for(left=0,right=count;left<=count/2;left++,right--){
    
    
                        temp=s[left];
                        s[left]=s[right];
                        s[right]=temp;
                }
                write(fe[1],s,30);
                wait(0);
        }
}

operation result:
insert image description here

analyze:

Call pipe(fd); After creating a pipe, then call the fork() function to generate two processes, first start executing the child process, close the pipe exit, and write content to the pipe through the pipe entrance. In the parent process, the pipe entry is closed, the previously written content is read from the pipe through the pipe exit end, and finally output is output.

2. Task 2

(1) Read the program in Example 2, run the program once, then use the ipcs command to check the status of the shared memory in the system, execute the program again, and then use the ipcs command to check the status of the shared memory in the system, and perform the two results. Compare and analyze the reasons. Finally, use the ipcrm command to delete the shared storage area created by yourself.
Example 2:

#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int main()
{
    
    
	key_t key=15;
	int shmid_1,shmid_2;
	if ((shmid_1=shmget(key,1000,0644|IPC_CREAT))==-1){
    
    
        perror("shmget shmid_1");exit(1);
	}
	printf("First shared memory identifier is %d\n",shmid_1);
	if ((shmid_2=shmget(IPC_PRIVATE,20,0644))==-1){
    
    
        perror("shmget shmid_2");exit(2);
	}
	printf("Second shared memory identifier is %d\n",shmid_2);
	exit(0);
}

Running result:
Run the program for the first time, and then use the ipcs command to check the status of the shared storage area in the system. The results are as follows:

Run the program for the second time, and then use the ipcs command to view the status of the shared storage area in the system. The results are as follows:
insert image description here

Analysis:
shmget() is to create a new shared area or return an existing shared memory area descriptor; int shmgetkey_t key, int size, int shmflag), where key is the shared area number specified by the user, and size is the shared memory area The length of shmflag is used to identify the creation condition machine and access permission of the shared memory segment. If successful, the identifier of the shared memory segment is returned, which is used to uniquely identify an object in the kernel. For each shared memory segment that exists in the kernel storage space, the kernel maintains a data structure shmid_ds for it; if it fails, it returns -1 and sets errno.
The second shared identifier at the end of the two runs is not the same. Therefore, when viewing with ipcs, the keywords, shared memory identifiers, access rights, bytes, etc. in the shared memory segment are different.

(2) Each student logs in to two windows, first run example 3 program 1 in one window (or only log in to one window, first run program 1 in the background mode in this window), and then run example 3 in another window Program 2, observe and analyze the running results of the program. After running, you can use ctrl+c to end the running of program 1.

Example 3 (Program 1)

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

#define SHMKEY 75
#define K  1024
int shmid;
void cleanup()
{
    
    
shmctl(shmid,IPC_RMID,0);
exit(0);
 }

int main()
{
    
    
        int i, * pint;
        char* addr;
        for (i = 0; i < 20; i++) signal(i, cleanup);
        shmid = shmget(SHMKEY, 16 * K, 0777 | IPC_CREAT); /*建立16K共享区SHMKEY */
        addr = shmat(shmid, 0, 0);/*挂接,并得到共享区首地址 */
        printf("addr 0x%s\n", addr);
        pint = (int*)addr;
        for (i = 0; i < 256; i++) *pint++ = i;
        pause();/*等待接收进程读 */
}

Example 3 (Program 2)

#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define SHMKEY 75  
#define K  1024
int shmid;
int main (){
    
    
        int i,*pint;
        char *addr;
        shmid=shmget(SHMKEY,8*K,0777);/*取共享区SHMKEY的id */
        addr=(char *)shmat(shmid,0,0);/*连接共享区*/
        pint=(int *)addr;
        for (i=0;i<256;i++)
        printf("%d\n",*pint++);/*打印共享区中的内容*/
        return 0;
}

Experimental results:
insert image description here

Analysis:
First, the system deletes the memory segment pointed to by the predefined shmid by calling shmctl, then the system calls shmget to create a shared memory segment of 16 1024 bytes, and successfully returns the identifier of the shared memory segment to shmid, and then the system calls again shmat connects the memory segment and returns the address addr where the shared memory segment is connected to the address space of the calling process.
When program 1 runs, the program starts to execute, the system calls shmget to create a
shared memory segment of 8 1024 bytes, and then calls shmat to mount the memory segment, the system selects the mount address, and finally outputs the converted mount address. Finally output the content of the first 255. The shared memory area mechanism only provides the operating conditions for the communication process to access the shared memory area, and the synchronization control of the communication can only be completed by relying on the semaphore mechanism.

(3) Write a program: use the system calls shmget(), shmat(), shmdt(), shmctl() to program. Requires that a 30-byte long private shared memory segment be generated in the parent process. Next, set a character pointer to the shared memory segment, and write a string of uppercase letters to the memory area pointed to by the pointer. Call fork() to spawn a child process and let the child process display the contents of the shared memory segment. Next, the uppercase letters are changed to lowercase, and the child process modifies the contents of the shared memory. After that, the child process will detach the shared memory segment and exit. After the parent process sleeps for 5 seconds, the content in the shared memory segment (it is already lowercase at this time) is displayed here.
Write the program as follows:

#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define SHMKEY 200
#define K 1024
int shmid_1,shmid_2;
int main ()
{
    
    
    int x,y,i,*pint;
    char *addr_1,*addr_2;
    char words[5]={
    
    'A','B','C','D','E'};
    shmid_1=shmget(SHMKEY,30*K,0777|IPC_CREAT); /*建立16K共享区SHMKEY */
    addr_1=shmat(shmid_1,0,0);/*挂接,并得到共享区首地址*/
    pint=(int *)addr_1;
    printf ("addr_1 0x%x\n",addr_1);
    for (i=0;i<5;i++) {
    
    
            *pint=words[i];
            pint++;
    }
    while((x=fork())==-1);
    if(x==0){
    
    
        shmid_2=shmget(SHMKEY,30*K,0777|IPC_CREAT); /*建立16K共享区SHMKEY */
        addr_2=shmat(shmid_2,0,0);/*挂接,并得到共享区首地址*/
        pint=(int *)addr_2;
        for(i=0;i<5;i++){
    
    
            printf("%c ",*pint);
            *pint=*pint+32;
            pint++;
    	}
        printf("\n");
        y=shmdt(addr_2);
        exit(0);
    }else{
    
    
        sleep(5);
        pint=(int *)addr_1;
        for(i=0;i<5;i++){
    
    
            printf("%c ",*pint);
            pint++;
        }
        printf("\n");
    }
    return 0; 
}

Experimental results:
insert image description here

Guess you like

Origin blog.csdn.net/david2000999/article/details/122504414