Linux/UNIX Threads (1)

Source: Internet
Author: User
Tags exit in
Thread (1) This article describes how to use multiple control threads to execute multiple tasks in a single process environment. All threads in a process can access the components of the process (for example

Thread (1)

This article describes how to use multiple control threads to execute multiple tasks in a single process environment.

All threads in a process can access the components of the process (such as file descriptor and memory ).

The thread contains information required to indicate the execution environment in the process, this includes the thread ID, a set of register values, stacks, scheduling priorities and policies, signal shielding characters, errno variables, and thread private data that identify a thread in a process. All information about a process is shared with all threads of the process, including executable program text, global memory and heap memory of the program, stack, and file descriptor.

Thread ID

The process ID is unique throughout the system. Each thread ID is valid only in the process environment to which it belongs.

In a thread, the thread ID type is pthread_t. because the threads in Linux adopt the POSIX standard, the types of pthread_t are different in different systems. for example, in ipvtn, is of the unsigned long type, while in the solaris system, it is of the unsigned int type. The structure pointer is used on FreeBSD. Therefore, you cannot directly use = for interpretation, but use pthread_equal for judgment.

# Include

Intpthread_equal (pthread_t t1, pthread_t t2 );

Return value: if the values are equal, a non-0 value is returned. otherwise, 0 is returned.

The thread can call

# Include

Pthread_tpthread_self (void );

The return value is the thread of the calling thread.

Thread creation
You can call the pthread_create function to create a thread.

# Include

Intpthread_create (pthread_t * thread, const pthread_attr_t * attr,

Void * (* start_routine) (void *), void * arg );

Return value: if the request succeeds, 0 is returned. Otherwise, the error number is returned.

When pthread_create is returned successfully, the memory unit pointed to by the thread is set as the thread ID of the newly created thread. The attr parameter is used to customize various thread attributes. Set attr to NULL to create a thread with the default attribute.

The newly created thread starts running from the start_routine function address. this function has only one non-type pointer parameter arg. if more than one parameter needs to be passed to the start_routine function, you need to put these parameters in a structure, and then pass the address of this structure as the arg parameter.

When a thread is created, it cannot be guaranteed which thread will run first: whether it is a newly created thread or a calling thread. The newly created thread can access the address space of the process and inherit the floating point environment of the calling thread and the signal shielding word, but the pending signal set of the thread is cleared.

The following program creates a thread and prints the process ID, the thread ID of the new thread, and the thread ID of the initialization thread.

[Cpp] view plaincopyprint? 01. # include
02. # include
03. # include
04.
05. pthread_t ntid;
06.
07. void printids (const char * s)
08 .{
09. pid_t pid;
10. pthread_t tid;
11.
12. pid = getpid ();
13. tid = pthread_self ();
14. printf ("% s pid % u tid % u (0x % x) \ n", s, (unsigned int) pid,
15. (unsigned int) tid, (unsigned int) tid );
16 .}
17.
18. void * thr_fn (void * arg)
19 .{
20. printids ("new thread :");
21. return (void *) 0 );
22 .}
23.
24. void err_quit (const char * fmt ,...)
25 .{
26. printf ("% s \ n", fmt );
27. exit (1 );
28 .}
29.
30.
31. int main (void)
32 .{
33. int err;
34.
35. err = pthread_create (& ntid, NULL, thr_fn, NULL );
36. if (err! = 0)
37. err_quit ("can't create thread: % s \ n", strerror (err ));
38. printids ("main thread :");
39. sleep (1 );
40. exit (0 );
41 .}
# Include
# Include
# Include

Pthread_t ntid;

Void printids (const char * s)
{
Pid_t pid;
Pthread_t tid;

Pid = getpid ();
Tid = pthread_self ();
Printf ("% s pid % u tid % u (0x % x) \ n", s, (unsigned int) pid,
(Unsigned int) tid, (unsigned int) tid );
}

Void * thr_fn (void * arg)
{
Printids ("new thread :");
Return (void *) 0 );
}

Void err_quit (const char * fmt ,...)
{
Printf ("% s \ n", fmt );
Exit (1 );
}


Int main (void)
{
Int err;

Err = pthread_create (& ntid, NULL, thr_fn, NULL );
If (err! = 0)
Err_quit ("can't create thread: % s \ n", strerror (err ));
Printids ("main thread :");
Sleep (1 );
Exit (0 );
}

Compile:

The pthread library is not the default library in Linux. you must use the static library libpthread for connection. a, you need to link to this library when using pthread_create () to create a thread and calling the pthread_atfork () function to create a fork handler.

Gcc creatThread. c-lpthread

Execution and output:

./A. out

Main thread: pid2846 tid 3079362240 (0xb78b56c0)

New thread: pid 2846 tid 3079359344 (0xb78b4b70)

The main thread needs to sleep; otherwise, the whole process may be terminated before the new thread enters the running state. The new thread uses pthread_self () to obtain its own thread ID, rather than reading it from the shared memory or receiving it as a parameter from the thread's startup routine. The pthread_create function returns the ID of the new thread through the first parameter. In this example, the new thread ID is placed in ntid, but if the new thread runs before the main thread calls pthread_create to return, the new thread sees uninitialized ntid content.

Thread termination

If any thread in the process calls exit, _ Exit, or _ exit, the whole process is terminated. Similarly, if the default signal action is to terminate the process, sending the signal to the thread will terminate the whole process.

But the thread can exit in the following three ways:

1. the thread only returns from the startup routine. the returned value is the exit code of the thread.

2. the thread can be canceled by other threads in the same process.

3. the thread calls pthread_exit.

Pthread_exit function:

# Include

Voidpthread_exit (void * retval );

Retval is a non-typed pointer, similar to a single parameter passed to the startup routine. Other threads in the process can access this pointer by calling the pthread_join function.

# Include

Intpthread_join (pthread_t thread, void ** retval );

Return value: if the request succeeds, 0 is returned. Otherwise, the error number is returned.

The thread that calls the pthread_join function will be blocked until the specified thread calls pthread_exit, returns from the startup routine, or is canceled. If the thread only returns from its startup routine, retval will contain the return code. If the thread is canceled, the memory unit specified by retval is set to PTHREAD_CANCELED.

[Cpp] view plaincopyprint? 01. # include
02. # include
03. # include
04.
05. void * thr_fn1 (void * arg)
06 .{
07. printf ("thread 1 returning \ n ");
08. return (void *) 1 );
09 .}
10.
11. void * thr_fn2 (void * arg)
12 .{
13. printf ("thread 2 exiting \ n ");
14. pthread_exit (void *) 2 );
15 .}
16. voiderr_quit (const char * fmt ,...)
17 .{
18. printf ("% s \ n", fmt );
19. exit (1 );
20 .}
21. int main (void)
22 .{
23. int err;
24. pthread_t tid1, tid2;
25. void * tret;
26.
27. err = pthread_create (& tid1, NULL, thr_fn1, NULL );
28. if (err! = 0)
29 .{
30. err_quit ("can't create thread 1: % s \ n", strerror (err ));
31.
32 .}
33. err = pthread_create (& tid2, NULL, thr_fn2, NULL );
34. if (err! = 0)
35. err_quit ("can't create thread 2: % s \ n", strerror (err ));
36. err = pthread_join (tid1, & tret );
37. if (err! = 0)
38. err_quit ("can 'tjoin with thread 1: % s \ n", strerror (err ));
39. printf ("thread 1 exitcode % d \ n", (int) tret );
40. err = pthread_join (tid2, & tret );
41. if (err! = 0)
42. err_quit ("can 'tjoin with thread 2: % s \ n", strerror (err ));
43. printf ("thread 2 exitcode % d \ n", (int) tret );
44. exit (0 );
45 .}
# Include
# Include
# Include
 
Void * thr_fn1 (void * arg)
{
Printf ("thread 1 returning \ n ");
Return (void *) 1 );
}
 
Void * thr_fn2 (void * arg)
{
Printf ("thread 2 exiting \ n ");
Pthread_exit (void *) 2 );
}
Voiderr_quit (const char * fmt ,...)
{
Printf ("% s \ n", fmt );
Exit (1 );
}
Int main (void)
{
Int err;
Pthread_t tid1, tid2;
Void * tret;
 
Err = pthread_create (& tid1, NULL, thr_fn1, NULL );
If (err! = 0)
{
Err_quit ("can't create thread 1: % s \ n", strerror (err ));
 
}
Err = pthread_create (& tid2, NULL, thr_fn2, NULL );
If (err! = 0)
Err_quit ("can't create thread 2: % s \ n", strerror (err ));
Err = pthread_join (tid1, & tret );
If (err! = 0)
Err_quit ("can 'tjoin with thread 1: % s \ n", strerror (err ));
Printf ("thread 1 exitcode % d \ n", (int) tret );
Err = pthread_join (tid2, & tret );
If (err! = 0)
Err_quit ("can 'tjoin with thread 2: % s \ n", strerror (err ));
Printf ("thread 2 exitcode % d \ n", (int) tret );
Exit (0 );
}

Run and output:

Thread 2 exiting

Thread 1 returning

Thread 1 exit code 1

Thread 2 exit code 2

It can be seen that when a thread exits by calling pthread_exit or simply returning from the startup routine, other threads in the process can obtain the exit status of the thread by calling the pthread_join function.

The non-type pointer parameters of the pthread_exit and pthread_create functions may pass an address of a complex structure. after the singular value is called, the memory callers used by this structure must still be valid. You can use the global structure or the malloc function to allocate the stack structure.

The thread can call the pthread_cancel function to cancel other threads in the same process.

# Include

Int pthread_cancel (pthread_t thread );

Return value: if successful, 0 is returned; otherwise, an error number is returned.

By default, the pthread_cancel function will make the thread identified by the thread behave as if the pthread_exit function with the parameter PTHREAD_CANCELED is called, but the thread can choose to ignore the cancellation method or control the cancellation method.

The thread can schedule the function to be called when it exits, which is similar to the function that the process can use the atexit function to schedule the function to be called when the process exits. Such a function becomes a thread cleanup handler. Threads can create multiple cleanup programs. The handlers are recorded in the stack, that is, they are executed in the opposite order as they were registered.

# Include

Voidpthread_cleanup_push (void (* routine) (void *), void * arg );

Voidpthread_cleanup_pop (int execute );

The cleanup function is called when the thread executes the following actions. the call parameter is arg. the call sequence of the cleanup function routine is arranged by the pthread_cleanup_push function.

1. when pthread_exit is called

2. response to the cancellation request

3. when voidpthread_cleanup_pop is called using the non-zero execute parameter

If execute is 0, the cleanup function is not called. In either case, pthread_cleanup_pop will delete the cleanup handler created by the last pthread_cleanup_push call.

The following program shows how to use a thread to clean up the handler.

[Cpp] view plaincopyprint? 01. # include
02. # include
03. # include
04.
05. void cleanup (void * arg)
06 .{
07. printf ("cleanup: % s \ n", (char *) arg );
08 .}
09.
10. void * thr_fn1 (void * arg)
11 .{
12. printf ("thread 1 start \ n ");
13. pthread_cleanup_push (cleanup, "thread 1 first handler ");
14. pthread_cleanup_push (cleanup, "thread 1 second handler ");
15. printf ("thread 1 push complete \ n ");
16. if (arg)
17. return (void *) 1 );
18. pthread_cleanup_pop (0 );
19. pthread_cleanup_pop (0 );
20. return (void *) 1 );
21 .}
22.
23. void * thr_fn2 (void * arg)
24 .{
25. printf ("thread2 start \ n ");
26. pthread_cleanup_push (cleanup, "thread 2 first handler ");
27. pthread_cleanup_push (cleanup, "thread 2 second handler ");
28. printf ("thread2 push complete \ n ");
29. if (arg)
30. pthread_exit (void *) 2 );
31. pthread_cleanup_pop (0 );
32. pthread_cleanup_pop (0 );
33. pthread_exit (void *) 2 );
34 .}
35.
36. void err_quit (const char * fmt ,...)
37 .{
38. printf ("% s \ n", fmt );
39. exit (1 );
40 .}
41.
42. int main (void)
43 .{
44. int err;
45. pthread_t tid1, tid2;
46. void * tret;
47.
48. err = pthread_create (& tid1, NULL, thr_fn1, (void *) 1 );
49. if (err! = 0)
50. err_quit ("can't create thread 1: % s \ n", strerror (err ));
51. err = pthread_create (& tid2, NULL, thr_fn2, (void *) 1 );
52. if (err! = 0)
53. err_quit ("can't create thread 2: % s \ n", strerror (err ));
54. err = pthread_join (tid1, & tret );
55. if (err! = 0)
56. err_quit ("can't join with thread 1: % s \ n", strerror (err ));
57. printf ("thread1 exit code % d \ n", (int) tret );
58. err = pthread_join (tid2, & tret );
59. if (err! = 0)
60. err_quit ("can't join with thread 2: % s \ n", strerror (err ));
61. printf ("thread2 exit code % d \ n", (int) tret );
62. exit (0 );
63 .}
# Include
# Include
# Include
 
Void cleanup (void * arg)
{
Printf ("cleanup: % s \ n", (char *) arg );
}
 
Void * thr_fn1 (void * arg)
{
Printf ("thread 1 start \ n ");
Pthread_cleanup_push (cleanup, "thread 1 first handler ");
Pthread_cleanup_push (cleanup, "thread 1 second handler ");
Printf ("thread 1 push complete \ n ");
If (arg)
Return (void *) 1 );
Pthread_cleanup_pop (0 );
Pthread_cleanup_pop (0 );
Return (void *) 1 );
}
 
Void * thr_fn2 (void * arg)
{
Printf ("thread2 start \ n ");
Pthread_cleanup_push (cleanup, "thread 2 first handler ");
Pthread_cleanup_push (cleanup, "thread 2 second handler ");
Printf ("thread2 push complete \ n ");
If (arg)
Pthread_exit (void *) 2 );
Pthread_cleanup_pop (0 );
Pthread_cleanup_pop (0 );
Pthread_exit (void *) 2 );
}
 
Void err_quit (const char * fmt ,...)
{
Printf ("% s \ n", fmt );
Exit (1 );
}
 
Int main (void)
{
Int err;
Pthread_t tid1, tid2;
Void * tret;
 
Err = pthread_create (& tid1, NULL, thr_fn1, (void *) 1 );
If (err! = 0)
Err_quit ("can't create thread 1: % s \ n", strerror (err ));
Err = pthread_create (& tid2, NULL, thr_fn2, (void *) 1 );
If (err! = 0)
Err_quit ("can't create thread 2: % s \ n", strerror (err ));
Err = pthread_join (tid1, & tret );
If (err! = 0)
Err_quit ("can't join with thread 1: % s \ n", strerror (err ));
Printf ("thread1 exit code % d \ n", (int) tret );
Err = pthread_join (tid2, & tret );
If (err! = 0)
Err_quit ("can't join with thread 2: % s \ n", strerror (err ));
Printf ("thread2 exit code % d \ n", (int) tret );
Exit (0 );
}

The execution and output results are as follows:

Thread 2 start

Thread 2 push complete

Cleanup: thread 2 second handler

Cleanup: thread 2 first handler

Thread 1 start

Thread 1 push complete

Thread 1 exit code 1

Thread 2 exit code 2

The output shows that both threads start and exit correctly, but only the cleanup handler of the second thread is called, therefore, if a thread is terminated by returning it from its startup routine, its cleanup handler will not be called, note that cleanup programs are called in the reverse order of their installation.

The separation status of a thread determines how a thread terminates itself. By default, threads are not separated. in this case, the original thread waits for the creation of the thread to end. Only when the pthread_join () function returns, the created thread is terminated and the system resources occupied by it can be released. The separation thread is not like this. it is not waiting by other threads. when the running ends, the thread is terminated and system resources are released immediately, calling pthread_join on the thread in the separation state can result in failure and return EINVAL. The pthread_detach call can be used to separate threads.

# Include

Intpthread_detach (pthread_t thread );

Return value: if successful, 0 is returned; otherwise, an error number is returned.

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.