"Operating System Principles" Experiment Report Three

1. The purpose of the experiment
(1) Understand the thread/process communication mechanism and programming;
(2) Understand the concept of thread/process deadlock and how to solve the deadlock

2. Experimental content
(1) Create a pair of parent-child processes in Ubuntu or Fedora environment, and use shared memory to achieve inter-process communication. The parent process provides data (1-100, increment), and the child process reads it out and displays it.
(2) (Considering the signal communication mechanism) Create two processes A and B, father and son, in Ubuntu or Fedora environment. Process A continuously obtains the string or integer entered by the user from the keyboard, and transmits it to process B through the signal mechanism. If the input is a character string, process B will print it out; if the input is an integer, process B will add it up and output the number and the accumulated sum. When the cumulative sum is greater than 100, the child process ends, the child process outputs "My work done!" and then ends, and then the parent process also ends.
(3) Create a pair of parent-child processes in the windows environment, and use pipes to achieve inter-process communication. The parent process provides data (1-100, increment), and the child process reads it out and displays it.
(4) (Consider anonymous channel communication) Create and encapsulate the CMD console program as a standard windows window program in the windows environment.
(5) In the windows environment, use the high-level language programming environment (limited to VS environment or VC environment or QT) to call the CreateThread function philosopher's dining problem demonstration. Requirements: (1) Provide deadlock solutions and non-deadlock solutions; (2) There is a graphical interface to visually display the states of philosophers taking chopsticks, eating, putting chopsticks, and thinking. (3) In order to enhance the randomness of the results, the maintenance time between each state adopts a random time, for example, between 100ms and 500ms.
:Any 1 question and 2nd and 5th questions in [1,3,4], a total of 3 questions

3. Experimental process
(1) Experimental steps
1) Use shared memory to realize inter-process communication
1. What is shared memory?
Shared memory is to allow two unrelated processes to access the same logical memory. The memory shared between different processes is usually arranged as the same physical memory. Processes can connect the same segment of shared memory to their own address space, and all processes can access addresses in shared memory.
2. Important function introduction:
declared in the header file sys/shm.h.
shmget function: this function is used to create Shared memory
int shmget(key_t key, size_t size, int shmflg);
key_t key: It effectively names the shared memory segment. When the shmget function succeeds, it returns a shared memory identifier (non-negative integer) related to the key. The call fails and returns -1.
size_t size: size specifies the amount of memory that needs to be shared in bytes
int shmflg: permission flag for shared memory
shmat function: shmat function is used to start access to the shared memory, and share The memory is connected to the address space of the current process
void *shmat(int shm_id, const void *shm_addr, int shmflg);
shm_id: shm_id is the shared memory identifier returned by the shmget function.
shm_addr: shm_addr specifies the address location where the shared memory is connected to the current process, usually empty, which means that the system is allowed to select the address of the shared memory.
shmflg: shm_flg is a set of flag bits, usually 0.
shmdt function: This function is used to separate shared memory from the current process so that the shared memory is no longer available to the current process.
int shmdt(const void *shmaddr); The
parameter shmaddr: is the address pointer returned by the shmat function. It returns 0 when the call is successful, and returns -1 when it fails.
shmctl function: Same as the semctl function of the semaphore, used to control shared memory
int shmctl( int shm_id, int command, struct shmid_ds *buf);
shm_id: is the shared memory identifier returned by the shmget function.
command: is the operation to be taken, it can take the following three values:
IPC_STAT: Set the data in the shmid_ds structure to the current associated value of the shared memory, that is, overwrite the value of shmid_ds with the current associated value of the shared memory.
IPC_SET: If the process has sufficient permissions, set the current associated value of the shared memory to the value given in the shmid_ds structure.
IPC_RMID: delete the shared memory segment
buf: is a structure pointer that points to the shared memory mode and access permissions structure.
1.

	if (pid < 0)    
2.	   {
    
        
3.	       //printf('子进程创建失败');    
4.	       fprintf(stderr, "can't fork ,error %d\n", errno);    
5.	       exit(1);    
6.	   }    
7.	   else if (pid == 0) //子进程    
8.	   {
    
        
9.	       while (cRunning) //读取共享内存中的数据    
10.	       {
    
        
11.	           //没有进程向共享内存定数据有数据可读取    
12.	           if (shared->written != 0)    
13.	           {
    
        
14.	               int i = 0;    
15.	               while (i < 100)    
16.	               {
    
        
17.	                   printf("child  read: %d\n", shared->text[i]);    
18.	                   i++;    
19.	               }    
20.	               //读取完数据,设置written使共享内存段可写    
21.	               shared->written = 0;    
22.	               //退出循环(程序)    
23.	               cRunning = 0;    
24.	           }    
25.	           else //有其他进程在写数据,不能读取数据    
26.	               sleep(1);    
27.	       }    
28.	   }    
29.	   else //父进程    
30.	   {
    
        
31.	       int i = 1;    
32.	       while (pRunning) //向共享内存中写数据    
33.	       {
    
        
34.	           //数据还没有被读取,则等待数据被读取,不能向共享内存中写入文本    
35.	           while (shared->written == 1)    
36.	           {
    
        
37.	               sleep(1);    
38.	           }    
39.	           //向共享内存中写入数据    
40.	           shared->text[i - 1] = i;    
41.	           printf("parent write: %d\n", shared->text[i - 1]);    
42.	           i++;    
43.	           if (i > 100)    
44.	           {
    
        
45.	               //写完数据,设置written使共享内存段可读,退出循环(程序)    
46.	               shared->written = 1;    
47.	               pRunning = 0;    
48.	           }    
49.	       }    
50.	   }   

2) Use the signal communication mechanism to achieve inter-process communication. A
process can send a signal to other processes including itself by calling the kill function. If the program does not have permission, the kill function will fail. The common reason for the failure is that the target process is owned by another user. This function has exactly the same function as the shell command kill with the same name. It is defined as follows:
#include <sys/types.h>
# include <signal.h>
int kill(pid_t pid, int sig); In the
kill function, pid represents the process id of the target process to be sent, and sig is the value of the signal sent.
On success, 0 is returned. On failure, it returns -1, and errno variable
because the signal is not transmitted communication data, so that in conjunction with the pipe communication
how to communicate between the conduit processes
create the pipe (1) parent, to give two ends pointing to the file descriptors conduit
( 2) The parent process forks the child process, and the sub process also has two file descriptors pointing to the same pipe.
(3) The parent process closes fd[0] and the child process closes fd[1], that is, the process closes the pipe reading end, sub The process closes the writing end of the pipe (because the pipe only supports one-way communication). A process can write to the pipe, and a subprocess can read from the pipe. The pipe is implemented using a circular queue. Data flows from the writing end to the reading end, thus realizing inter-process communication.
Insert picture description here

3) Demonstration of the philosopher's meal problem
Chopstick number: 0-4 (The chopsticks on the left hand side of the philosopher are the same as his own number)
int S[5]={1,1,1, 1,1}; //Semaphore: No. i Whether chopsticks are available: 0 is not available, 1 is available
UINT Philosopher (int i)//Thread function, i is the number of the philosopher
{while (TRUE){ Thinking; Rest; P(S[i]); //Take the left hand side Chopsticks P(S[(i+4)% 5]); //Take the chopsticks on the right hand side and eat; //Using two chopsticks... V(S[(i+4)% 5]); //Let down The chopsticks on the right hand side V(S[i); //Put down the chopsticks on the left hand side} } Core code: //Create 5 semaphores for(int i=0;i<5;i++){ S[i] = CreateSemaphore (NULL ,1 ,1,name[i]); } //Open the semaphore: HANDLE right,left; left =OpenSemaphore(SEMAPHORE_ALL_ACCESS,FALSE,name[id]); right=OpenSemaphore(SEMAPHORE_ALL_ACCESS,FALSE,name[( id+4)%5]); WaitForSingleObject(left,INFINITE); //p operation


















ReleaseSemaphore(left,1,NULL); //v operation
(two) error resolution and optimization
1. Compilation error, cannot be converted from const char * to LPCWSTR. Reason: Because your program runs under the UNICODE (wide byte) character set, if you call MessageBox, it actually calls the MessageBoxW function; if your program runs in the ANSI character set, calling MessageBox is equivalent to calling essenceBoxA; Among them, MessageBoxW supports UNICODE; MessageBoxA supports ANSI; What is the difference between UNICODE and ANSI? Simply put, the UNICODE version of the character takes up more memory than the ANSI. For example, the standard definition char in Win32 programs occupies one byte, and the UNICODE version of char is defined as follows: typedef unsigned short wchar_t; occupies 2 bytes . Therefore, the functions that have characters as parameters also use two versions.
Solution: Project menu-project properties (last one)-configuration properties-general-project default value-character set, just change the Unicode character set to unset.
2. Special syntax error, linux c prompt format'%d' expects argument of type'int', but argument 2 has type'long int'. Solution md, m is the width of the specified output field. If the number of digits of the data is less than m, a space is added to the left end, and if it is greater than m, the actual number of digits is output. %ld (%mld is also available), output long integer data. Finally printf("data is %ld", data) is resolved.
Summary: %md, m is the width of the specified output field. If the number of digits of the data is less than m, a space is added to the left end, and if it is greater than m, the actual number of digits is output. %ld (%mld is also available), output long integer data. U format symbol, used to output unsigned type data, unsigned number, output in decimal form. Format: %u, %mu, %lu are all acceptable
3. Special syntax error, variable declaration is repeated. Error analysis: The variable "xxxx" is defined multiple times in the same scope. Check every definition of "xxxx", keep only one, or change the variable name.
4. test.c:59:5: warning: incompatible implicit declaration of built-in function'memset' [enabled by default], add header file: #include<string.h> to solve.

4. Experimental results
1) Use shared memory to achieve inter-process communication
as shown in the figure below
Insert picture description here
Insert picture description here

2) Use shared memory to achieve inter-process communication
Insert picture description here

3) Demonstration of philosopher's meal problem
Insert picture description here
Insert picture description here

V. Experience
Through this experiment, I have a deeper understanding of the operating system thread/process communication mechanism and programming, and the concept of deadlock of operating system threads/processes. I have mastered how to solve deadlocks and have a better understanding of the functions of the operating system. The principle has been further understood.

Guess you like

Origin blog.csdn.net/weixin_45341339/article/details/112413422