Creation and use of Linux C threads [Go]

Source: Internet
Author: User
Tags function prototype mutex semaphore

1 Introduction
Threading (thread) technology was introduced in the 60 's, but the real application of multithreading to the operating system was in the middle of the 80 's, and Solaris was a leader in this area. Traditional UNIX also supports threading concepts, but only one thread is allowed in a process, so multi-threading means multiple processes. Multithreaded technology is now supported by many operating systems, including WINDOWS/NT, and of course, Linux.
Why do we have to introduce threads when we have the concept of a process? What are the benefits of using multithreading? What system should choose Multi-threading? We must first answer these questions.
One of the reasons to use multithreading is that it is a very "frugal" multi-tasking approach compared to the process. We know that under the Linux system, starting a new process must be assigned to its own address space, creating numerous data tables to maintain its code snippets, stack segments, and data segments, which is an "expensive" multi-tasking way of working. While running on multiple threads in a process that use the same address space, sharing most of the data, starting a thread is much less than the space it takes to start a process, and the time it takes to switch between threads is much less than the time it takes to switch between processes. According to statistics, in general, the cost of a process is about 30 times times the cost of a thread, of course, on a specific system, this data may be significantly different.
The second reason to use multithreading is the convenient communication mechanism between threads. For different processes, they have independent data space, it is not only time-consuming, but also inconvenient to transmit the data only by means of communication. Threads do not, because data space is shared between threads in the same process, so that the data of one thread can be used directly by other threads, which is not only fast, but also convenient. Of course, the sharing of data also brings some other problems, some variables can not be modified by two threads at the same time, some of the sub-programs declared as static data more likely to have a catastrophic attack on the multi-threaded program, these are the most important to write a multi-thread programming.
In addition to the advantages mentioned above, not compared with the process, multi-threaded procedure as a multi-tasking, concurrent work, of course, the following advantages:
1) Improve application response. This is especially meaningful to the graphical interface program, when an operation takes a long time, the entire system waits for this operation, the program does not respond to the keyboard, mouse, menu operation, and the use of multi-threading technology, the time-consuming operation (consuming) into a new thread, can avoid this embarrassing situation.
2) Make multi-CPU system more effective. The operating system guarantees that when the number of threads is not greater than the number of CPUs, different threads run on different CPUs.
3) Improve the program structure. A long and complex process can be considered to be divided into multiple threads and become a separate or semi-independent part of the run, which facilitates understanding and modification.
Let's start by trying to write a simple multithreaded program.

2 Simple Multithreaded programming
Multithreading under a Linux system follows the POSIX threading interface, called Pthread. To write multithreaded programs under Linux, you need to use the header file Pthread.h, you need to use the library libpthread.a when connecting. By the way, the implementation of Pthread under Linux is implemented through the system call Clone (). Clone () is a Linux-specific system call that is used in a manner similar to fork, with details about clone () that interested readers can look at for documentation instructions. Below we show one of the simplest multi-threaded example1.c.

/* example.c*/
#include
#include
void thread (void)
{
int i;
for (i=0;i<3;i++)
printf ("This is a pthread.\n");
}

int main (void)
{
pthread_t ID;
int I,ret;
Ret=pthread_create (&id,null, (void *) thread,null);
if (ret!=0) {
printf ("Create pthread error!\n");
Exit (1);
}
for (i=0;i<3;i++)
printf ("This is the main process.\n");
Pthread_join (Id,null);
return (0);
}

We compile this program:
GCC example1.c-lpthread-o example1
Running example1, we get the following results:
This is the main process.
This is a pthread.
This is the main process.
This is the main process.
This is a pthread.
This is a pthread.
Run again, we may get the following result:
This is a pthread.
This is the main process.
This is a pthread.
This is the main process.
This is a pthread.
This is the main process.

The results are different for two times, which is the result of two threads competing for CPU resources. In the example above, we used two functions, pthread_create and Pthread_join, and declared a variable of type pthread_t.
pthread_t is defined in the header file/usr/include/bits/pthreadtypes.h:
typedef unsigned long int pthread_t;
It is the identifier of a thread. The function pthread_create is used to create a thread whose prototype is:
extern int pthread_create __p ((pthread_t *__thread, __const pthread_attr_t *__attr,
void * (*__start_routine) (void *), void *__arg));
The first argument is a pointer to the thread identifier, the second parameter sets the Thread property, the third argument is the starting address of the thread's running function, and the last parameter is the argument that runs the function. Here, our function thread does not require arguments, so the last parameter is set to a null pointer. The second parameter we also set as a null pointer, which will generate the default properties of the thread. The setting and modification of thread properties is described in the next section. When creating a line Cheng, the function returns 0, if not 0, the creation thread fails, and the common error return code is eagain and einval. The former indicates that the system restricts the creation of new threads, such as excessive number of threads, which indicates that the second parameter represents an illegal thread property value. After the thread is created successfully, the newly created thread runs the function identified by parameter three and parameter four, and the original thread continues to run the next line of code.
The function pthread_join is used to wait for the end of a thread. The function prototypes are:
extern int Pthread_join __p ((pthread_t __th, void **__thread_return));
The first parameter is the waiting thread identifier, and the second parameter is a user-defined pointer that can be used to store the return value of the waiting thread. This function is a thread-blocking function, and the function that invokes it waits until the thread that is waiting ends, and when the function returns, the resource that is waiting for the thread is retracted. There are two ways to end a thread, one is like our example above, the function ends, the thread that calls it ends, and the other is implemented by the function Pthread_exit. Its function prototypes are:
extern void Pthread_exit __p ((void *__retval)) __attribute__ ((__noreturn__));
The only argument is the return code of the function, as long as the second parameter in Pthread_join Thread_return is not NULL, this value is passed to Thread_return. Finally, one thread cannot be waited by multiple threads, or the first line that receives the signal Cheng returns, and the remaining thread that calls Pthread_join returns the error code esrch.
In this section, we have written one of the simplest threads and mastered the three most commonly used functions pthread_create,pthread_join and pthread_exit. Let's look at some of the common properties of threads and how to set these properties.

3 Modify the properties of a thread
in the example in the previous section, we created a thread with the Pthread_create function, in which we used the default parameters, The second parameter of the function is set to NULL. Indeed, for most programs, using the default properties is enough, but we still need to know about the properties of the thread. The
Property structure is pthread_attr_t, which is also defined in the header file/usr/include/pthread.h, and people who like inquisitive can see for themselves. The property value cannot be set directly, it must be manipulated using the correlation function, the function initialized is pthread_attr_init, and the function has to be called before the Pthread_create function. Property objects mainly include whether to bind, detach, stack address, stack size, priority. The default properties are unbound, non-detached, default 1M stacks, and the same level of precedence as the parent process. The
binding on threads involves another concept: light processes (lwp:light Weight process). A light process can be understood as a kernel thread, which is located between the user layer and the system layer. The system's allocation of thread resources, the control of threads is achieved through a light process, and a light process can control one or more threads. By default, how many light processes are started and which light processes control which threads are controlled by the system, which is called Unbound. Binding state, the name implies that a thread fixed "tied" on a light process. The bound thread has a high response speed because the CPU time slice is scheduled for a lightweight process, and the bound thread can guarantee that it always has a light process available when needed. By setting the priority and dispatch level of the lightweight process being bound, the bound thread can satisfy requirements such as real-time response. The
function for setting the thread binding state is Pthread_attr_setscope, which has two parameters, the first is a pointer to the property structure, the second is the binding type, and it has two values: Pthread_scope_system (bound) and Pthread_ Scope_process (non-binding). The following code creates a bound thread.
#include
pthread_attr_t attr;
pthread_t tid;

/* Initialize attribute values, set to default values */
Pthread_attr_init (&ATTR);
Pthread_attr_setscope (&attr, Pthread_scope_system);

Pthread_create (&tid, &attr, (void *) my_function, NULL);

Another potentially common attribute is the priority of the thread, which is stored in the structure Sched_param. Using function Pthread_attr_getschedparam and function Pthread_attr_setschedparam to store, generally speaking, we always first take priority, the value of the obtained modified and then stored back. The following is a simple example.
#include
#include
pthread_attr_t attr;
pthread_t Tid;
Sched_param param;
int newprio=20;

pthread_attr_init (&attr);
Pthread_attr_getschedparam (&ATTR,¶M);
Param.sched_priority=newprio;
Pthread_attr_setschedparam (&attr,¶m);
Pthread_create (&tid, &attr, (void *) MyFunction, myarg);

4 Thread data processing
One of the greatest advantages of threading compared to a process is the sharing of data, where each process shares the data segment inherited by the parent process, which makes it easy to obtain and modify the data. But this also brings a lot of problems to multithreaded programming. We must beware of having multiple different processes accessing the same variable. Many functions are non-reentrant, which means that multiple copies of a function cannot be run at the same time (unless different data segments are used). Static variables declared in a function often cause problems, and the return value of a function can be problematic. Because if the address of the space that is statically declared inside the function is returned, the other thread might call this function and modify the piece of data when a thread calls the function to get the address and uses the data that the address points to. Variables shared in the process must be defined with the keyword volatile to prevent the compiler from changing how they are used when optimizing, such as using the-ox parameter in GCC. In order to protect variables, we must use semaphores, mutexes and other methods to ensure that the correct use of variables. Below, we'll step through the knowledge of threading data.

4.1 thread data
in a single-threaded program, there are two basic types of data: global variables and local variables. In multithreaded programs, however, there is a third type of data: Thread data (tsd:thread-specific). It is much like a global variable, inside a thread, functions can be called as if they were global variables, but it is invisible to other threads outside the thread. The need for such data is obvious. For example, our common variable, errno, returns a standard error message. It obviously cannot be a local variable, almost every function should be able to invoke it, but it cannot be a global variable, otherwise the output in a thread is likely to be a B-thread error message. To implement variables like this, we have to use thread data. We create a key for each thread data, which is associated with this key, which is used in each thread to refer to thread data, but in different threads, the key represents a different data, and in the same thread, it represents the same data content. There are 4 main functions related to thread data: Create a key, specify thread data for a key, read thread data from a key, delete a key. The function prototype for the
Create key is:
extern int pthread_key_create __p ((pthread_key_t *__key,
Void (*__destr_function) (void *))); br> The first parameter is a pointer to a key value, the second parameter indicates a destructor function, and if the argument is not NULL, then the system calls this function to release the block of memory bound to the key when each thread ends. This function is often used in conjunction with the function pthread_once ((Pthread_once_t*once_control, Void (*initroutine)), in order for the key to be created only once. The function pthread_once declares an initialization function that executes the function the first time it is called pthread_once, and the subsequent invocation is ignored by it.

In the following example, we create a key and associate it with some data. To define a function CreateWindow, this function defines a graphics window (data type Fl_window *, which is the data type in the graphical interface development tool FLTK). Because each thread calls this function, we use thread data.
/* Declare a key */
pthread_key_t Mywinkey;
/* Function CreateWindow */
void CreateWindow (void) {
Fl_window * WIN;
static pthread_once_t once= pthread_once_init;
/* Call function Createmykey, create key */
Pthread_once (& Once, Createmykey);
/*win points to a newly created window */
Win=new Fl_window (0, 0, +, +, "Mywindow");
/* Some possible setup work for this window, such as size, location, name, etc. */
SetWindow (Win);
/* Bind the window pointer value on the key Mywinkey */
Pthread_setpecific (Mywinkey, Win);
}

/* Function Createmykey, create a key, and specify destructor */
void Createmykey (void) {
Pthread_keycreate (&mywinkey, Freewinkey);
}

/* function Freewinkey, free space */
void Freewinkey (Fl_window * win) {
Delete win;
}

In this way, calling the function Createmywin in different threads can get the window variables that are visible inside the thread, and this variable is obtained through the function pthread_getspecific. In the example above, we have used the function pthread_setspecific to bind the thread data with a key. The prototypes of these two functions are as follows:
extern int pthread_setspecific __p ((pthread_key_t __key,__const void *__pointer));
extern void *pthread_getspecific __p (pthread_key_t __key);
The parameter meanings and usage of these two functions are obvious. Note that when you use Pthread_setspecific to specify new thread data for a key, you must release the original thread data yourself to reclaim the space. This process function pthread_key_delete is used to delete a key, the memory that the key occupies will be freed, but it is also important to note that it only frees the memory used by the key, does not release the memory resource that is consumed by the thread data associated with the key, and it does not trigger the function Pthread_key_ The destructor function defined in Create. The release of the thread data must be completed before the key is released.

4.2 Mutual exclusion Lock
Mutexes are used to guarantee that only one thread is executing a piece of code over a period of time. The necessity is obvious: assuming that each thread writes data sequentially to the same file, the final result must be catastrophic.
Let's look at the following piece of code first. This is a read/write program that is common to a buffer, and we assume that a buffer can hold only one message. That is, the buffer has only two states: there is information or no information.

void reader_function (void);
void writer_function (void);

char buffer;
int buffer_has_item=0;
pthread_mutex_t Mutex;
struct TIMESPEC delay;
void Main (void) {
pthread_t reader;
/* Define delay time */
Delay.tv_sec = 2;
Delay.tv_nec = 0;
/* Initialize a mutex object with default properties */
Pthread_mutex_init (&mutex,null);
Pthread_create (&reader, Pthread_attr_default, (void *) &reader_function), NULL);
Writer_function ();
}

void Writer_function (void) {
while (1) {
/* Lock the Mutex */
Pthread_mutex_lock (&mutex);
if (buffer_has_item==0) {
Buffer=make_new_item ();
Buffer_has_item=1;
}
/* Open Mutex */
Pthread_mutex_unlock (&mutex);
PTHREAD_DELAY_NP (&delay);
}
}

void Reader_function (void) {
while (1) {
Pthread_mutex_lock (&mutex);
if (buffer_has_item==1) {
Consume_item (buffer);
buffer_has_item=0;
}
Pthread_mutex_unlock (&mutex);
PTHREAD_DELAY_NP (&delay);
}
}
The mutex variable mutex is declared here, and the struct pthread_mutex_t is a data type that is not exposed, which contains a system-assigned Property object. The function pthread_mutex_init is used to generate a mutex lock. A null parameter indicates that the default property is used. If you need to declare a mutex for a particular property, call the function Pthread_mutexattr_init. The function pthread_mutexattr_setpshared and the function Pthread_mutexattr_settype are used to set the Mutex property. The previous function sets the property pshared, which has two values, pthread_process_private, and pthread_process_shared. The former is used for thread synchronization in different processes, and the latter is used to synchronize different threads of the process. In the example above, we are using the default attribute Pthread_process_ PRIVATE. The latter is used to set the mutex type, and the optional types are pthread_mutex_normal, Pthread_mutex_errorcheck, pthread_mutex_recursive, and PTHREAD _mutex_default. They define the different mechanisms of the upper, the unlock, and, in general, the last default attribute.
The Pthread_mutex_lock declaration begins with a mutex lock, and thereafter the code is locked until the call Pthread_mutex_unlock, i.e. only one thread can invoke execution at the same time. When a thread executes to pthread_mutex_lock, if the lock is being used by another thread at this point, the thread is blocked, that is, the program waits for the other thread to release the mutex. In the example above, we used the PTHREAD_DELAY_NP function to get the thread to sleep for a while to prevent a thread from always occupying this function.
The above example is very simple, no longer introduced, it is necessary to use the mutex is likely to deadlock: two threads trying to occupy two resources at the same time, and in different order to lock the corresponding mutex, for example, two threads need to lock the mutex 1 and the mutex 2,a thread first lock the mutex lock 1, The b thread locks the mutex 2 first, and then a deadlock occurs. At this point we can use the function Pthread_mutex_trylock, which is a non-blocking version of the function Pthread_mutex_lock, when it finds that deadlock is unavoidable, it returns the appropriate information, and the programmer can handle the deadlock accordingly. In addition, different types of mutexes do not deal with deadlocks, but the main thing is for programmers to pay attention to this in their own programming.

4.3 Item variables
In the previous section we talked about how to use mutexes to share and communicate data between threads, and one obvious disadvantage of mutexes is that it has only two states: locking and non-locking. The condition variable compensates for the lack of a mutex by allowing the thread to block and wait for another thread to send a signal, which is often used in conjunction with a mutex. When used, a condition variable is used to block a thread, and when the condition is not met, the thread often unlocks the corresponding mutex and waits for the condition to change. Once another thread changes the condition variable, it notifies the corresponding condition variable to wake one or more threads that are being blocked by this condition variable. These threads will re-lock the mutex and re-test whether the condition is satisfied. In general, conditional variables are used to synchronize between lines.
The structure of the condition variable is pthread_cond_t, and the function Pthread_cond_init () is used to initialize a condition variable. Its prototype is:
extern int Pthread_cond_init __p ((pthread_cond_t *__cond,__const pthread_condattr_t *__cond_attr));
Where cond is a pointer to the structure pthread_cond_t, cond_attr is a pointer to the structure pthread_condattr_t. The structure pthread_condattr_t is the property structure of the condition variable, and the same as the mutex we can use it to set whether the condition variable is available in process or between processes, the default value is Pthread_ process_private, That is, this condition variable is used by individual threads within the same process. Note that initialization condition variables can be reinitialized or released only if they are not in use. The function that releases a condition variable is pthread_cond_ destroy (pthread_cond_t cond).
The function pthread_cond_wait () causes the thread to block on a condition variable. Its function prototypes are:
extern int pthread_cond_wait __p (pthread_cond_t *__cond,
pthread_mutex_t *__mutex));
The thread unlocks the lock that the mutex points to and is blocked by the condition variable cond. The thread can be awakened by the function pthread_cond_signal and the function pthread_cond_broadcast, but it is important to note that the condition variable only acts as a blocking and wake-up thread, and the specific judging condition needs to be given by the user, such as whether a variable is 0, etc. We can see this in the following example. After the thread is awakened, it will recheck to see if the condition is satisfied, and if it is not satisfied, the thread should still be stuck here, waiting for the next wake-up. This process is typically implemented with a while statement.
Another function to block a thread is pthread_cond_timedwait (), which is a prototype:
extern int pthread_cond_timedwait __p (pthread_cond_t *__cond,
pthread_mutex_t *__mutex, __const struct timespec *__abstime);
It is more than a function pthread_cond_wait () a time parameter, after the abstime period of time, even if the condition variable is not satisfied, blocking is also lifted.
The prototype of the function pthread_cond_signal () is:
extern int pthread_cond_signal __p ((pthread_cond_t *__cond));
It is used to release a thread that is blocked on the condition variable cond. When multiple threads block on this condition variable, which thread is awakened is determined by the thread's scheduling policy. It is important to note that this function must be protected with a mutex that protects the condition variable, otherwise the condition satisfies the signal and may be emitted between the test condition and the call pthread_cond_wait function, resulting in an unrestricted wait. Here is a simple example of using the function pthread_cond_wait () and the function pthread_cond_signal ().

pthread_mutex_t Count_lock;
pthread_cond_t Count_nonzero;
unsigned count;
Decrement_count () {
Pthread_mutex_lock (&count_lock);
while (count==0)
Pthread_cond_wait (&count_nonzero, &count_lock);
count=count-1;
Pthread_mutex_unlock (&count_lock);
}

Increment_count () {
Pthread_mutex_lock (&count_lock);
if (count==0)
Pthread_cond_signal (&count_nonzero);
count=count+1;
Pthread_mutex_unlock (&count_lock);
}
When the count value is 0 o'clock, the decrement function is blocked at pthread_cond_wait and open the mutex count_lock. At this point, when called to the function Increment_count, the pthread_cond_signal () function changes the condition variable to tell Decrement_count () to stop blocking. The reader can try to get two threads to run the two functions separately to see what happens.
The function pthread_cond_broadcast (pthread_cond_t *cond) is used to wake up all threads that are blocked on the condition variable cond. These threads are awakened and will compete for the corresponding mutex again, so you must use this function with care.

4.4 Signal Volume
The semaphore is essentially a nonnegative integer counter that is used to control access to public resources. When the public resources increase, the call function Sem_post () increases the semaphore. A public resource can be used only if the semaphore value is greater than 0 o'clock, and the function sem_wait () reduces the semaphore after use. The function sem_trywait () and the function Pthread_ Mutex_trylock () play the same role, which is the non-blocking version of the function sem_wait (). Here we describe some of the functions related to semaphores, which are defined in the header file/usr/include/semaphore.h.
The data type of the semaphore is the structure sem_t, which is essentially a number of long integers. The function Sem_init () is used to initialize a semaphore. Its prototype is:
extern int Sem_init __p ((sem_t *__sem, int __pshared, unsigned int __value));
SEM is a pointer to a semaphore structure; pshared is not 0 o'clock this semaphore is shared between processes, otherwise it can only be shared for all threads of the current process; value gives the initial value of the semaphore.
The function sem_post (sem_t *sem) is used to increase the value of the semaphore. When a thread is blocked on this semaphore, calling this function causes one of the threads to not block, and the selection mechanism is also determined by the thread's scheduling policy.
The function sem_wait (sem_t *sem) is used to block the current thread until the value of the semaphore SEM is greater than 0, and the value of the SEM is reduced by one after unblocking, indicating that the public resources are decreased after use. The function sem_trywait (sem_t *sem) is a non-blocking version of the function sem_wait (), which directly minimizes the value of the semaphore SEM.
The function Sem_destroy (sem_t *sem) is used to release the signal volume of the SEM.
Let's take a look at an example of using semaphores. In this example, there are 4 threads, two of which are responsible for reading data from a file to a common buffer, and two threads reading data from the buffer for different processing (plus and multiply operations).
/* File SEM.C */
#include
#include
#include
#define MAXSTACK 100
int stack[maxstack][2];
int size=0;
sem_t sem;
/* Read data from file 1.dat, each time the semaphore is added a/*
void ReadData1 (void) {
FILE *fp=fopen ("1.dat", "R");
while (!feof (FP)) {
FSCANF (FP, "%d%d", &stack[size][0],&stack[size][1]);
Sem_post (&sem);
++size;
}
Fclose (FP);
}
/* Read data from file 2.dat */
void ReadData2 (void) {
FILE *fp=fopen ("2.dat", "R");
while (!feof (FP)) {
FSCANF (FP, "%d%d", &stack[size][0],&stack[size][1]);
Sem_post (&sem);
++size;
}
Fclose (FP);
}
/* Block wait buffers have data, after reading data, free space, continue to wait */
void HandleData1 (void) {
while (1) {
Sem_wait (&sem);
printf ("plus:%d+%d=%d\n", stack[size][0],stack[size][1],
STACK[SIZE][0]+STACK[SIZE][1]);
--size;
}
}

void HandleData2 (void) {
while (1) {
Sem_wait (&sem);
printf ("multiply:%d*%d=%d\n", stack[size][0],stack[size][1],
STACK[SIZE][0]*STACK[SIZE][1]);
--size;
}
}
int main (void) {
pthread_t T1,t2,t3,t4;
Sem_init (&sem,0,0);
Pthread_create (&t1,null, (void *) handledata1,null);
Pthread_create (&t2,null, (void *) handledata2,null);
Pthread_create (&t3,null, (void *) readdata1,null);
Pthread_create (&t4,null, (void *) readdata2,null);
/* Prevent the program from exiting prematurely and let it wait indefinitely */
Pthread_join (T1,null);
}

Under Linux, we use the command gcc-lpthread sem.c-o sem to generate the executable file SEM. We edit the data files in advance 1.dat and 2.dat, assuming that their content is 1 2 3 4 5 6 7 8 9 10 and-1-2-3-4-5-6-7-8-9-10, we run the SEM, get the following results:
multiply:-1*-2=2
Plus:-1+-2=-3
Multiply:9*10=90
Plus:-9+-10=-19
multiply:-7*-8=56
Plus:-5+-6=-11
Multiply:-3*-4=12
Plus:9+10=19
Plus:7+8=15
plus:5+6=11

From this we can see the competitive relationship between the various threads. And the values are not shown in our original order. This is because the value of size is arbitrarily modified by each thread. This is also often the problem of multithreading programming to pay attention to.

5 Summary
Multithreaded programming is a very interesting and useful technology, the use of multi-threaded network ant is one of the most commonly used download tools, using multi-threading technology grep than single-threaded grep a few times faster, similar examples are many. I hope you can use multithreading technology to write efficient and practical good program.

===================================================================================================

The creation of threads is implemented using several functions below.

#include int pthread_create (pthread_t *thread,pthread_attr_t *attr,void * (*start_routine) (void *), void *arg); void Pthread_exit (void *retval); int Pthread_join (pthread *thread,void **thread_return);

Pthread_create creates a thread that is used to indicate that the thread created by id,attr refers to the attribute at the time of creation, and we use NULL to indicate the use of the default. The Start_routine function pointer is a function that starts executing after the thread is created successfully, and ARG is the only parameter to the function. Indicates the arguments passed to the start_routine.

The Pthread_exit function and the Exit function are similar to exiting a thread. This function ends the thread, frees the function's resources, and then blocks until the other thread waits for it with the Pthread_join function. The value of *retval is then passed to **thread_return. Because this function frees the function resources, retval cannot point to local variables of the function.

The Pthread_join and wait calls are used just as waiting for the specified thread. Let's use an example to explain how to use it. In practice, we often have to back up some files. The following program can be used to implement all file backups in the current directory. The suffix named bak after backup

Creation and use of Linux C threads [Go]

Related Article

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.