Foreword
On UNIX hosts, threads are often referred to as "lightweight processes", which is simple to understand, in fact, UNIX threads are evolved from the process. Compared with the process, the thread is quite small, and the CPU overhead caused by creating threads is relatively small. Not only that, but because the thread can share memory resources, it is also available to use threads to save memory. Several articles will focus on the most common part of the POSIX thread standard (mainly based on its implementation on DEC OSF / 1 OS, V3.0).
Hello World
The function used by creating a process is pthread_create (). Its four parameters include: a pointer of a thread (pthread_t) variable, a thread attribute (pthread_attr_t) variable, pointer to the thread, the function pointer to which the thread is started, and one parameter (Void *) passed to the function.
pthread_t a_thread; pthread_attr_t a_thread_attribute; void * thread_function (void * argument); char * some_argument; pthread_create (& a_thread, a_thread_attribute, thread_function, (void *) some_argument);
Many times, thread attribute variables only specify the minimum stack used by threads. In fact, it has a richer meaning, but now, most applications create a new thread value, but a pthread_attr_default, sometimes even NULL. The new thread created with pthread_create () starts from the specified function portal, which is different from the creation process: all processes have the same execution sequence. This is a simple reason: If all processes are executed from the same process space, there will be multiple processes to perform the same interlocking of the same shared resource.
Now we already know how to create a new thread, let us start the first multi-thread program: export "Hello World" with multiple threads on the screen. To display the role of the thread, we will use two threads: one is used to output "Hello" and the other is used to output "world". To this end, we first need a function for screen output, which will start from this function. In addition, we need two threads (pthread_t) variables to create new threads. Of course, we need to indicate the strings that each new thread should output in the parameters of pthread_create (). Please see the following code:
void * print_message_function (void * ptr); main () {pthread_t thread1, thread2; char * message1 = "Hello"; char * message2 = "World"; pthread_create (& thread1, pthread_attr_default, print_message_function, (void *) message1); pthread_create (& thread2, pthread_attr_default, print_message_function, (void *) message2); exit (0);} void * print_message_function (void * ptr) {char * message; message = (char *) ptr; printf ( "% s", message) Here, you need to pay attention to the prototype of the Print_Message_Function () function, and the conversion of the parameter type when the new thread is created. The program first creates the first new thread and passes "hello" as a parameter, and then another thread is created and "world" is passed as the starting parameter. We hope that the first thread starts from printf_message_function (), ends after outputting "Hello", then the second thread ends after the output "WORLD" is also ended. Such a process seems to be very reasonable, but there are two serious defects.
First, different threads are run in parallel and have no order. So we cannot guarantee that the first new thread outputs a string before the second thread. As a result, the screen output may be "Hello World" or may be "World Hello". Second, similar to the above reasons, the parent thread (so called) may execute exit (0) before the two sub-thread output, which will result in the end of the entire process - of course, the two sub-processs will end. The consequence is that there may be no output at all on the screen. In order to solve the second problem, we can use pthread_exit () instead of Exit (), which will not end (because the function does not terminate the running of the entire process).
At present, our applet has two competitive conditions, and now let us try to solve them with a relatively stupid approach. First, in order to run the two suborders in the order we need, we insert a delay before creating the second thread. Then, in order to ensure that the parent thread does not exit before the end of the sub-thread, we also insert a delay in the end of the parent thread. Please see the following code:
void * print_message_function (void * ptr); main () {pthread_t thread1, thread2; char * message1 = "Hello"; char * message2 = "World"; pthread_create (& thread1, pthread_attr_default, print_message_function, (void *) message1); sleep (10); pthread_create (& thread2, pthread_attr_default, print_message_function, (void *) message2); sleep (10); exit (0);} void * print_message_function (void * ptr) {char * message; message = (char *) ptr PRINTF ("% s", message); pthread_exit (0);} Regret, the above code still does not meet our purpose. Thread synchronization is very unreliable by delaying. The synchronous problem we have currently encountered is inherently the same as synchronous problems in distributed programming: we will never make aware of the thread that will end when it will end. The defects of the above code are not just unreliable. In fact, when the Sleep () function is executed, the entire process is sleeping, not just a parent thread, which is very similar to exit (). When Sleep () returns, our programs are still facing the same conditions. Our new code not only does not solve competition, but let us spend 20 seconds to wait for the end of the program. By the way, if you want to delay a certain thread, you should call the pthread_delay_np () function (NP means Non Portable, not portable), as follows:
Struct Timespec Delay; delay.tv_sec = 2; delay.tv_nsec = 0; pthread_delay_np (& delay);
The functions involved in this section: pthread_create (), pthread_exit (), pthread_delay_np ().