POSIX thread (2)

Source: Internet
Author: User

The first thread Program

There is a complete set of thread-related database calls, most of which start with pthread. To use these library calls, we must define macro _ reentrant, including the file pthread. H, and use-lpthread to link the thread library.

When the original UNIX and POSIX library functions are designed, it is assumed that there is only one execution thread in any process. An obvious example is errno. This variable is used to obtain error information after the call fails. In a multi-threaded program, only one variable is shared among threads by default. A call in one thread can easily update this variable before another thread obtains the previous error code. Similar programs exist in functions, such as fputs. A global region is usually used to cache output.

We need to call it a reentrant routine. The re-entry code can be called multiple times, whether it is a different thread or embedded call, and can work normally. Therefore, local variables must be used for the reusable code, so that each call to this code can obtain a unique copy of data.

In multi-threaded programs, we define the _ reentrant macro before any # include code in the program to notify the compiler that we need this feature. This will do three things for us, and we usually do not need to know what to do for us:

Some functions have the same prototype as reentrant functions. They usually have the same function name, but add _ R after the function name. For example, gethostbyname is changed to gethostbyname_r.

Generally, some stdio. h functions in macro implementation become suitable reentrant security functions.

The variable errno in errno. h is used to call a function. This function can ensure the real errno value in a multi-thread safe way.

The pthread. h file contains other definitions and prototypes required in our code, similar to stdio. h for standard input and output routines. Finally, we need to ensure that we include the correct header file and link to the correct thread library to implement the pthread function. We will learn more about the experiment later.

Pthread_create creates a new thread, similar to fork creating a new process.

# Include <pthread. h>
Int pthread_create (pthread_t * thread, pthread_attr_t * ATTR, void
* (* Start_routine) (void *), void * Arg );

This seems complicated, but it is actually easy to use. The first parameter is a pointer to pthread_t. After a thread is created, an identifier is written to the variable pointed to by this pointer. This identifier allows us to reference this thread. The next parameter sets the thread attributes. We usually do not need special properties, and we can simply pass a null as a parameter. Later in this chapter, we will learn how to use these attributes. The last two parameters indicate the thread function to be executed and the parameter to be passed to this function.

Void * (* start_routine) (void *)

The previous line simply indicates that we must pass a function address with the void pointer as the parameter, and this function will return a pointer to void. Therefore, we can pass a single parameter of any type and return a pointer to any type. Using fork will enable the program to continue executing with different Returned Code at the same position, while using the new thread to explicitly provide a function pointer at the start of a new thread.

If the operation succeeds, the function returns 0. If an error occurs, an error code is returned. The manual page provides a detailed description of this function and the error conditions of other functions used in this chapter.

Note: pthread_create, similar to most pthread_functions functions, is a few UNIX functions that do not follow-1 as the function to return error code. Unless we are very certain, the most secure way is to view the manual page before detecting the error code.

When the thread ends, it calls the pthread_exit function, similar to calling exit when the process ends. The function ends the calling thread and returns a pointer to the object. Never use it to return a pointer to a local variable, because when the thread returns, the variable will no longer exist, causing a serious bug. The pthread_exit function declaration is as follows:

# Include <pthread. h>
Void pthread_exit (void * retval );

Pthread_join is the same thread function as the wait process function for collecting sub-processes. The declaration of this function is as follows:

# Include <pthread. h>
Int pthread_join (pthread_t th, void ** thread_return );

The first parameter is the thread to wait, and pthread_create is the identifier we created. The second parameter is a pointer to the pointer that is returned by the thread. Similar to the pthread_create function, this function returns zero if it succeeds. If it fails, an error code is returned.

Test-a simple thread Program

This program creates another thread, demonstrates that it shares variables with the original thread, and enables the new thread to return a result to the original thread. Multi-threaded programs won't be simpler than this! The following is thread1.c:

# Include <stdio. h>
# Include <unistd. h>
# Include <stdlib. h>
# Include <pthread. h>

Void * thread_function (void * Arg );

Char message [] = "Hello World ";

Int main ()
{
Int res;
Pthread_t a_thread;
Void * thread_result;

Res = pthread_create (& a_thread, null, thread_function, (void *) message );
If (res! = 0)
{
Perror ("thread creation failed ");
Exit (exit_failure );
}
Printf ("waiting for thread to finish.../N ");
Res = pthread_join (a_thread, & thread_result );
If (res! = 0)
{
Perror ("thread join failed ");
Exit (exit_failure );
}

Printf ("thread joined, it returned % s/n", (char *) thread_result );
Printf ("message is now % s/n", message );
Exit (exit_success );
}

Void * thread_function (void * Arg)
{
Printf ("thread_function is running. argumen was % s/n", (char *) Arg );
Sleep (3 );
Strcpy (message, "bye ");
Pthread_exit ("Thank you for the CPU time ");
}

1. to compile this program, first make sure that _ reentrant is defined. In some systems, we also need to define _ posix_c_source, but generally this is not necessary.

2. Now we must ensure that the correct library is connected. According to our system, nptl may not be the default by default, or in some old systems, it may not be available based on the kernel. Fortunately, most of the Code in this chapter is independent of the precise thread library used. In the author's system, the standard/usr/CE/pthread. h file shows that it is named linuxthreads and the copyright date is 1996, so it is obvious that this is an old library. To obtain a new nptl library, we need to install additional RPM packages to provide header files under/usr/include/nptl and provide libraries under/usr/lib/nptl.

3. After identifying and installing the correct file, we can use the following command to compile and link our program:

$ CC-d_reentrant-I/usr/include/nptl thread1.c-O thread1-L/usr/lib/nptl-lpthread

4. When we run this program, we will get the following output:

$./Thread1
Waiting for thread to finish...
Thread_function is running. argument was hello World
Thread joined, it returned thank you For the CPU time
Message is now bye!

It is worthwhile to take some time to understand this program, because we use it as the basis for most examples in this chapter.

Working Principle

We declared that a function prototype will be called when an online process is created.

Void * thread_function (void * Arg );

As required by the pthread_create function, it carries a pointer to void as its unique parameter and returns a pointer to void. We will introduce the function definition later.

In the main function, we declare some variables and call pthread_create to start our new thread.

Pthread_t a_thread;
Void * thread_result;
Res = pthread_create (& a_thread, null, thread_function, (void *) message );

We pass the address of a pthread_t object, and we can use it to reference this thread later. We do not want to modify the default thread attribute, So we pass a null as the second parameter. The last two parameters are the functions to be called and the parameters passed to them.

If the call is successful, two threads will be run now. The code after the original thread (main) continues to execute and executes pthread_create, and a new thread starts to execute the thread_function code.

The original thread detects that the new thread has started and then calls pthread_join.

Res = pthread_join (a_thread, & thread_result );

Here we pass a thread ID that we are waiting for the Union and a pointer to the result. This function will wait until another function ends before it returns. Then it outputs the return value of the thread and the content of the variable, and exits.

The new thread starts to execute and thread_function will output its parameters, sleep for a period of time, update the global variable, then exit, and return a string to the main thread. The new thread overrides the same Array and message as the original thread access. This is not the case if we call fork instead of pthread_create.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.