alp-ch04-threads(1).pdf
(
285 KB
)
Pobierz
../alp/advanced-linux-programming.pdf (5)
4
Threads
T
HREADS
,
LIKE PROCESSES
,
ARE A MECHANISM TO ALLOW A PROGRAM
to do more than
one thing at a time. As with processes, threads appear to run concurrently; the Linux
kernel schedules them asynchronously, interrupting each thread from time to time to
give others a chance to execute.
Conceptually, a thread exists within a process.Threads are a finer-grained unit of
execution than processes.When you invoke a program, Linux creates a new process
and in that process creates a single thread, which runs the program sequentially.That
thread can create additional threads; all these threads run the same program in the
same process, but each thread may be executing a different part of the program at any
given time.
We ’ve seen how a program can fork a child process.The child process is initially
running its parent’s program, with its parent’s virtual memory, file descriptors, and so
on copied.The child process can modify its memory, close file descriptors, and the like
without affecting its parent, and vice versa.When a program creates another thread,
though, nothing is copied.The creating and the created thread share the same memory
space, file descriptors, and other system resources as the original. If one thread changes
the value of a variable, for instance, the other thread subsequently will see the modi-
fied value. Similarly, if one thread closes a file descriptor, other threads may not read
62
Chapter 4 Threads
from or write to that file descriptor. Because a process and all its threads can be exe-
cuting only one program at a time, if any thread inside a process calls one of the
exec
functions, all the other threads are ended (the new program may, of course, create new
threads).
GNU/Linux implements the POSIX standard thread API (known as
pthreads
). All
thread functions and data types are declared in the header file
<pthread.h>
.The
pthread functions are not included in the standard C library. Instead, they are in
libpthread
, so you should add
-lpthread
to the command line when you link your
program.
4.1 Thread Creation
Each thread in a process is identified by a
thread ID
.When referring to thread IDs in
C or C++ programs, use the type
pthread_t
.
Upon creation, each thread executes a
thread function
.This is just an ordinary func-
tion and contains the code that the thread should run.When the function returns, the
thread exits. On GNU/Linux, thread functions take a single parameter, of type
void*
,
and have a
void*
return type.The parameter is the
thread argument
: GNU/Linux passes
the value along to the thread without looking at it.Your program can use this parame-
ter to pass data to a new thread. Similarly, your program can use the return value to
pass data from an exiting thread back to its creator.
The
pthread_create
function creates a new thread.You provide it with the following:
1. A pointer to a
pthread_t
variable, in which the thread ID of the new thread is
stored.
2. A pointer to a
thread attribute
object.This object controls details of how the
thread interacts with the rest of the program. If you pass
NULL
as the thread
attribute, a thread will be created with the default thread attributes.Thread
attributes are discussed in Section 4.1.5, “Thread Attributes.”
3. A pointer to the thread function.This is an ordinary function pointer, of this
type:
void* (*) (void*)
4. A thread argument value of type
void*
. Whatever you pass is simply passed as
the argument to the thread function when the thread begins executing.
A call to
pthread_create
returns immediately, and the original thread continues exe-
cuting the instructions following the call. Meanwhile, the new thread begins executing
the thread function. Linux schedules both threads asynchronously, and your program
must not rely on the relative order in which instructions are executed in the two
threads.
4.1 Thread Creation
63
The program in Listing 4.1 creates a thread that prints x’s continuously to standard
error. After calling
pthread_create
, the main thread prints o’s continuously to standard
error.
Listing 4.1
(
thread-create.c
) Create a Thread
#include <pthread.h>
#include <stdio.h>
/* Prints x’s to stderr. The parameter is unused. Does not return. */
void* print_xs (void* unused)
{
while (1)
fputc (‘x’, stderr);
return NULL;
}
/* The main program. */
int main ()
{
pthread_t thread_id;
/* Create a new thread. The new thread will run the print_xs
function. */
pthread_create (&thread_id, NULL, &print_xs, NULL);
/* Print o’s continuously to stderr. */
while (1)
fputc (‘o’, stderr);
return 0;
}
Compile and link this program using the following code:
% cc -o thread-create thread-create.c -lpthread
Try running it to see what happens. Notice the unpredictable pattern of x’s and o’s as
Linux alternately schedules the two threads.
Under normal circumstances, a thread exits in one of two ways. One way, as illus-
trated previously, is by returning from the thread function.The return value from the
thread function is taken to be the return value of the thread. Alternately, a thread can
exit explicitly by calling
pthread_exit
.This function may be called from within the
thread function or from some other function called directly or indirectly by the thread
function.The argument to
pthread_exit
is the thread’s return value.
64
Chapter 4 Threads
4.1.1 Passing Data to Threads
The thread argument provides a convenient method of passing data to threads.
Because the type of the argument is
void*
, though, you can’t pass a lot of data directly
via the argument. Instead, use the thread argument to pass a pointer to some structure
or array of data. One commonly used technique is to define a structure for each
thread function, which contains the “parameters” that the thread function expects.
Using the thread argument, it’s easy to reuse the same thread function for many
threads. All these threads execute the same code, but on different data.
The program in Listing 4.2 is similar to the previous example.This one creates two
new threads, one to print x’s and the other to print o’s. Instead of printing infinitely,
though, each thread prints a fixed number of characters and then exits by returning
from the thread function.The same thread function,
char_print
, is used by both
threads, but each is configured differently using
struct char_print_parms
.
Listing 4.2
(
thread-create2
) Create Two Threads
#include <pthread.h>
#include <stdio.h>
/* Parameters to print_function. */
struct char_print_parms
{
/* The character to print. */
char character;
/* The number of times to print it. */
int count;
};
/* Prints a number of characters to stderr, as given by PARAMETERS,
which is a pointer to a struct char_print_parms. */
void* char_print (void* parameters)
{
/* Cast the cookie pointer to the right type. */
struct char_print_parms* p = (struct char_print_parms*) parameters;
int i;
for (i = 0; i < p->count; ++i)
fputc (p->character, stderr);
return NULL;
}
/* The main program. */
int main ()
{
pthread_t thread1_id;
4.1 Thread Creation
65
pthread_t thread2_id;
struct char_print_parms thread1_args;
struct char_print_parms thread2_args;
/* Create a new thread to print 30,000 ’x’s. */
thread1_args.character = ’x’;
thread1_args.count = 30000;
pthread_create (&thread1_id, NULL, &char_print, &thread1_args);
/* Create a new thread to print 20,000 o’s. */
thread2_args.character = ’o’;
thread2_args.count = 20000;
pthread_create (&thread2_id, NULL, &char_print, &thread2_args);
return 0;
}
But wait!
The program in Listing 4.2 has a serious bug in it.The main thread (which
runs the
main
function) creates the thread parameter structures (
thread1_args
and
thread2_args
) as local variables, and then passes pointers to these structures to the
threads it creates.What’s to prevent Linux from scheduling the three threads in such a
way that
main
finishes executing before either of the other two threads are done?
Nothing!
But if this happens, the memory containing the thread parameter structures
will be deallocated while the other two threads are still accessing it.
4.1.2 Joining Threads
One solution is to force
main
to wait until the other two threads are done.What we
need is a function similar to
wait
that waits for a thread to finish instead of a process.
That function is
pthread_join,
which takes two arguments: the thread ID of the
thread to wait for, and a pointer to a
void*
variable that will receive the finished
thread’s return value. If you don’t care about the thread return value, pass
NULL
as the
second argument.
Listing 4.3 shows the corrected
main
function for the buggy example in Listing 4.2.
In this version,
main
does not exit until both of the threads printing x’s and o’s have
completed, so they are no longer using the argument structures.
Listing 4.3
Revised
Main
Function for
thread-create2.c
int main ()
{
pthread_t thread1_id;
pthread_t thread2_id;
struct char_print_parms thread1_args;
struct char_print_parms thread2_args;
continues
Plik z chomika:
musli_com
Inne pliki z tego folderu:
advanced-linux-programming(1).pdf
(3775 KB)
alp-apA-other-development-tools(2).pdf
(265 KB)
alp-apB-low-level-io(1).pdf
(246 KB)
alp-apC-signal-table(2).pdf
(173 KB)
alp-apD-online-resources(1).pdf
(144 KB)
Inne foldery tego chomika:
1_Security
2_Hack
3_Cryptography
4_Telecommunications
5_VoIP
Zgłoś jeśli
naruszono regulamin