Your understanding is not necessarily correct. It is for reference only. Do not copy it! The same is the same.
Lab 1
[Experiment Name]: concurrent program design (experiment 1)
[Objective]: to learn how to create a process in a program, observe and understand the phenomenon of concurrent execution of multiple programs.
[Experiment principle]: fork (): Creates a sub-process. The child process obtains a copy of the address space of the parent process.
Returned value: if the call succeeds, the function is called once, but two times are returned. fork () returns 0 to the child process and the child process identifier (not 0) to the parent process ). If the process fails,-1 is returned to the parent process, and no child process exists.
[Experiment content]: First, analyze the possibility of the output results when the program is running, then debug the program to observe the actual output, compare the differences between the two, and analyze the causes.
Void main (void)
{
Int x = 5;
If (fork ())
{
X + = 30;
Printf ("% d \ n", x );
}
Else
Printf ("% d \ n", x );
Printf ("% d \ n", x );
}
[Lab requirements]: Each student must complete the experiment independently, submit the lab report, source program and executable program. The lab report must contain expected lab results, key code analysis, debugging records, actual lab results, and experiment result analysis.
1. Key code analysis
An existing process can call the fork function to create a new process. A new process created by fork is called a child process ). The fork function is called once but returns two results. The only difference between the two responses is that the child process returns 0 and the parent process returns the child process ID.
A child process is a copy of the parent process. It obtains a copy of the data space, heap, stack, and other resources of the parent process. Note that sub-processes hold "copies" of the above bucket, which means that the parent and child processes do not share these buckets.
That is to say, when the program runs the if condition to determine whether to run the fork () function, the parent process runs the Code with the condition established, that is
X + = 30;
Printf ("% d \ n", x );
Sub-processes run code with invalid conditions, that is
Printf ("% d \ n", x );
Based on the working methods and features of concurrent execution, the expected experiment results are as follows:
2. Expected experiment results
There are six situations to guess (in fact, the entire four numbers are arranged)
35 |
35 |
35 |
5 |
5 |
5 |
35 |
5 |
5 |
5 |
35 |
35 |
5 |
35 |
5 |
35 |
5 |
35 |
5 |
5 |
35 |
35 |
35 |
5 |
Iii. debugging records
1. First create a document with the. c suffix, such as test. c.
2. Edit the source program:
# Include <stdio. h>
# Include <unistd. h>
Void main (void)
{
Int x = 5;
If (fork ())
{
X + = 30;
Printf ("% d \ n", x );
}
Else
Printf ("% d \ n", x );
Printf ("% d \ n", x );
}
3. Edit gcc-o test. out test. c In the command line.
Edit./test. out.
Run the program
4. Actual experiment results:
35
35
(A string of character commands, omitted) 5
5
(PS: That character command will appear after the parent process is run, so it will appear after two 35 outputs)
Repeat Step 3 and N times to find the result.
Iv. Analysis of experiment results
The teacher said that the appearance of other results is a small probability event. We do not agree. This can basically be considered as an impossible event.
So we guess this is related to the legendary time slice.
Because it takes too short time for the program to run. By default, the parent process that runs first can run completely in the time segment specified by the system. If nothing else happens, it will be suspended, the child process can only run after the parent process is completed.
So, of course, there is only one situation.
5. Experiment Result Processing
However, we can use the time slice feature to produce 6 results.
The main character debuted, sleep (1) one-second function Delay
The latency function can be understood as a piece of code that needs to run for 1 second. The process mentioned below is suspended because the time slice of the running process in this delay code is used up (for example, 0.6 seconds is run in this delay code, you can jump out of the latency function after 0.4 seconds.
First:
Because the parent process is run by default (the system I use is like this), we feel it is unfair to the child process, so the source code of the first case we create is:
# Include <stdio. h>
# Include <unistd. h>
Void main (void)
{Int x = 5;
If (fork ())
{
X + = 30;
Sleep (1 );
Printf ("% d \ n", x );
}
Else
Printf ("% d \ n", x );
Printf ("% d \ n", x );
}
We guess that the time slice is 0.6 seconds. Whether it is correct, the focus is analysis.
After the parent process runs for 0.6 seconds, the time slice is suspended and the sub-process is scheduled to run. After the sub-process runs, the sub-process is scheduled to run back to the parent process. So we guess the result is
5
5
35
35
(A string of character commands, omitted)
Wow, it is also finished!
Second:
Here we suddenly think of what if we add a latency function before the sub-process,
# Include <stdio. h>
# Include <unistd. h>
Void main (void)
{Int x = 5;
If (fork ())
{
X + = 30;
Sleep (1 );
Printf ("% d \ n", x );
}
Else {
Sleep (1 );
Printf ("% d \ n", x );
}
Printf ("% d \ n", x );
}
However, this can only be analyzed based on the answer after debugging, because we do not know the real time slice, just guess. The running result is
35
35
(A string of character commands, omitted) 5
5
We continue to assume that the time slice is 0.6 seconds, the parent process is suspended after 0.6 seconds of running, and the sub-process is suspended after 0.6 seconds of running. The sub-process is scheduled back to the parent process to continue running, because it has been running for 0.6 seconds, this scheduling time slice is enough. Assumption is true
Therefore, we assume that the time slice is 0.6 seconds. This time is reasonable.
Third:
# Include <stdio. h>
# Include <unistd. h>
Void main (void)
{
Int x = 5;
If (fork ())
{
X + = 30;
Sleep (1 );
Printf ("% d \ n", x );
}
Else {
Printf ("% d \ n", x );
Sleep (1 );
}
Printf ("% d \ n", x );
}
Similar to the preceding analysis, if a parent process is suspended after 0.6 seconds, the scheduling sub-process runs the first command and outputs x to 5, the system then suspends the function for 0.6 seconds (the time for running the preceding command is negligible), schedules it back to the parent process, and then schedules it back to the child process. Therefore, the output is
5
35
35
(A string of characters should be the command prompted for input, omitted) 5
Fourth:
# Include <stdio. h>
# Include <unistd. h>
Void main (void)
{Int x = 5;
If (fork ())
{
X + = 30;
Printf ("% d \ n", x );
Sleep (1 );
}
Else {
Printf ("% d \ n", x );
Sleep (1 );
}
Printf ("% d \ n", x );
}
The analysis is the same as above. The output result is
35
5
35
(A string of character commands, omitted) 5
Category 5:
# Include <stdio. h>
# Include <unistd. h>
Void main (void)
{Int x = 5;
If (fork ())
{
X + = 30;
Printf ("% d \ n", x );
Sleep (1 );
}
Else {
Printf ("% d \ n", x );
}
Printf ("% d \ n", x );
}
The running result is,
35
5
5
35
(A string of character commands, omitted)
Sixth:
Take a closer look at the five cases above, and you will find that there are still some wonderful ones that haven't appeared.
5
35
5
35
(A string of character commands, omitted)
From the parent process (delayed suspension) to the child process (output and then delayed suspension) to the parent process (delayed and output and then delayed suspension) to the child process (output end process) -> parent process (delay and output end process), Code:
# Include <stdio. h>
# Include <unistd. h>
Void main (void)
{Int x = 5;
If (fork ())
{
X + = 30;
Sleep (1 );
Printf ("% d \ n", x );
Sleep (1 );
}
Else {
Printf ("% d \ n", x );
Sleep (1 );
}
Printf ("% d \ n", x );
}