How to call Linux script in c language

  • 2020-04-02 01:17:19
  • OfStack

One, the introduction
Fork is one of the hardest concepts to understand for those who have never worked with the Unix/Linux operating system: it executes once and returns two values. The fork function is one of the most outstanding achievement in the Unix system, it is early Unix developers in the seventy s after a long hard exploration in the theory and practice achievements, on the one hand, it makes the operating system on the process management pay the minimum price, on the other hand, again for programmers to provide a clear and concise method of multiple processes. Unlike DOS and early Windows, Unix/Linux systems are truly multi-tasking systems, so to speak, you can't really program in a Linux environment without using multiple processes.

The concept of multithreaded programming was first proposed in the 1960s, but it wasn't until the mid-1980s that multithreading was introduced into Unix systems. Today, multithreaded programming has been widely used due to its many advantages.

Next, we'll introduce you to the basics of writing multiprocess and multithreaded programs under Linux.

Multiprocess programming
What is a process? The concept of a process is for the system, not for the user, for whom the concept is a program. When the user types in a command to execute a program, it starts a process for the system. But unlike programs, in this process, the system may need to start one or more more processes to complete separate tasks. The main content of multi-process programming includes process control and inter-process communication. Before we understand this, we need to know briefly the structure of the process.

2.1 process structure under Linux
The next Linux process has three parts of data in memory: the "code segment," the "stack segment," and the "data segment." In fact, people who have learned assembly language must know that the general CPU has the above three kinds of segment registers, in order to facilitate the operation of the operating system. These three parts are also necessary to form a complete execution sequence.

"Code snippet", as its name implies, is the data stored in the program code, if several processes in the machine run the same program, then they can use the same code snippet. The stack section holds the return address of the subroutine, its arguments, and its local variables. The data segment holds the program's global variables, constants, and data space allocated by dynamic data (such as the space obtained by functions such as malloc). There are a lot of details, which I won't go into here. If the system runs several identical programs at once, they cannot use the same stack segment and data segment among themselves.

2.2 process control under Linux
In a traditional Unix environment, there are two basic operations for creating and modifying processes: the function fork() is used to create a new process that is almost a full copy of the current process; The function family exec() is used to start another process to replace the currently running process. Linux process control is basically the same as traditional Unix process control, with only some differences in details, such as calling vfork on Linux systems is the same as calling fork, while on some versions of Unix, vfork calls have different functions. Since these differences barely affect most of our programming, we won't consider them here.

2.2.1 the fork ()
Fork means "to fork" in English. Why do you have that name? Because a process is running, if you fork it, you create another process, and the process "forks," so the name is pretty good. Here's a look at how to use fork specifically. This program demonstrates the basic framework for using fork:

void main()
    int i;
    if ( fork() == 0 ) 
       for ( i = 1; i <1000; i ++ ) 
          printf("This is child processn");
       for ( i = 1; i <1000; i ++ ) 
       printf("This is process processn");

Once the program is running, you can see a thousand messages printed by each of the child and parent processes alternately on the screen. If the program is still running, you can use the ps command to see that there are two of them running on the system.

So what happens when you call this fork? The fork function starts a new process, which, as mentioned earlier, is almost a copy of the current process: the child process and the parent process use the same code segment; The child process copies the stack and data segments of the parent process. In this way, all the data of the parent process can be left to the child process, but once the child process starts running, although it inherits all the data of the parent process, the data is actually separated from each other and no longer affects each other, that is, they no longer share any data with each other. When they want to interact with each other, they can do so only through interprocess communication, which is what we're going to do next. Since they are so similar, how can the system distinguish them? This is determined by the return value of the function. For the parent, the fork returns the subroutine's process number, and for the subroutine, the fork returns zero. In the operating system, we can use ps function to see different process Numbers, for the parent process, its process number is given by the system call at a lower level than it, and for the child process, its process number is the return value of the fork function to the parent process. In programming, both the parent and child process call the code below the function fork (), and we use the fork () function to return different values of the parent and child processes with if... The else... Statements to enable the parent and child processes to perform different functions, as in the example above. As we can see, the above example is executed with two pieces of information printed out interactively and irregularly, which is the result of separate execution by the parent and child processes, although our code seems to be no different from the serial code.

The reader may ask, if a large program is running, its data segments and stack are large, and each fork is replicated, isn't fork expensive? Actually UNIX has its solution, as we all know, the general CPU is based on "page" to allocate memory space for the unit, each page is an image of the actual physical memory, like INTEL CPU, under normal circumstances one page size is 4086 bytes, and both in data segment and the stack segment is made up of many "page", the fork function to copy these two section, just on the "logic", not "physics", in other words, when performing the fork, the actual physical space on both process data and stack or share, When a process writes some data, the data between the two processes is different, and the system physically separates the different pages. The space overhead of the system can be minimized.

Here's a demo of a small enough to "kill "Linux, the source code is very simple:

void main()
   for( ; ; )

The program does nothing but endlessly fork. The result is that the program continues to produce processes, and those processes continue to produce new processes. Of course, as long as the system administrator sets the maximum number of processes that each user can run in advance, this malicious program will not be able to complete the attempt.

2.2.2 exec() family of functions
Let's take a look at how one process starts the execution of another. In Linux you use the exec family of functions. The system call execve () replaces the current process with a specified program that takes a filename, a parameter list (argv), and an environment variable (envp). In Linux, they are respectively execl, execlp, execle, execv, execve and execvp. I will only take execlp as an example. What are the differences between other functions and execlp?

Once a process call exec class function, it is "death", the system USES the code to replace the new program code, abandoned the original data and stack section, as well as the distribution of new processes and new data segments stack section, the only thing left, is a process, that is to say, for the system, or the same process, but it's already another program. (but some of the exec functions also allow you to inherit information such as environment variables.)

So what if my program wants to start another program but I still want to run it? That's the combination of fork and exec. The following code shows how to start and run other programs:

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
char command[256];
void main()
   int rtn; 
   while(1) {
       printf( ">" );
       fgets( command, 256, stdin );
       command[strlen(command)-1] = 0;
       if ( fork() == 0 ) {
          execlp( command, NULL );
          perror( command );
          exit( errno );
       else {
          wait ( &rtn );
          printf( " child process return %dn", rtn );

This program reads the command from the terminal and executes it. After execution, the parent process continues to wait for the command to be read from the terminal. Those of you familiar with DOS and WINDOWS system calls will know that DOS/WINDOWS also has exec class functions, which are used in a similar way, but DOS/WINDOWS also has spawn class functions. Since DOS is a single-task system, it can only host the "parent process" in the machine and then execute the "child process", which is the function of spawn class. WIN32 is already a multitasking system, but it retains the spawn function, which is implemented in much the same way as in UNIX, with the parent process waiting for the child to finish. UNIX was a multitasking system in the first place, so there is no need to spawn class functions at the core.

In this section, we'll also talk about the system () and popen () functions. The system () function first calls fork (), then exec () to execute the user's login shell, looks up the commands for the executable, analyzes the arguments, and finally USES one of the wait () family of functions to wait for the end of the child process. The function popen () is similar to the function system () except that it calls the pipe () function to create a pipe through which the standard input and output of the program are completed. Both of these functions, designed for less diligent programmers, have significant performance and security drawbacks that should be avoided whenever possible.

Related articles: