Книга: Programming with POSIX® Threads
5.2.3 Thread attributes
5.2.3 Thread attributes
pthread_attr_t attr;
int pthread_attr_init (pthread_attr_t *attr);
int pthread_attr_destroy (pthread_attr_t *attr); int pthread_attr_getdetachstate (pthread_attr_t *attr, int *detachstate);
int pthread_attr_setdetachstate (pthread_attr_t *attr, int detachstate);
#ifdef _POSIX_THREAD_ATTR_STACKSIZE
int pthread_attr_getstacksize (pthread_attr_t *attr, size_t *stacksize);
int pthread_attr_setstacksize (pthread_attr_t *attr, size_t stacksize);
#endif
#ifdef _POSIX_THREAD_ATTR_STACKADDR
int pthread_attr_getstackaddr (pthread_attr_t *attr, void *stackaddr);
int pthread_attr_setstackaddr (pthread_attr_t *attr, void **stackaddr);
#endif
POSIX defines the following attributes for thread creation: detachstate, stack-size, stackaddr, scope, inheritsched, schedpolicy, and schedparam. Some systems won't support all of these attributes, so you need to check the system documentation before using them. You initialize a thread attributes object using pthread_ attr_init
, specifying a pointer to a variable of type pthread_attr_t
, as in the program thread_attr.c, shown later. You use the attributes object you've created by passing its address as the second argument to pthread_create
instead of the NULL value we've been using so far.
All Pthreads systems support the detachstate attribute. The value of this attribute can be either PTHREAD_CREATE_JOINABLE or PTHREAD_CREATE_DETACHED. By default, threads are created joinable, which means that the thread identification created by pthread_create
can be used to join with the thread and retrieve its return value, or to cancel it. If you set the detachstate attribute to PTHREAD_ CREATE_DETACHED, the identification of threads created using that attributes object can't be used. It also means that when the thread terminates, any resources it used can immediately be reclaimed by the system.
When you create threads that you know you won't need to cancel, or join with, you should create them detached. Remember that, in many cases, even if you want to know when a thread terminates, or receive some return value from it, you may not need to use pthread_join
. If you provide your own notification mechanism, for example, using a condition variable, you can still create your threads detached.
Setting the size of a stack is not very portable.
If your system defines the symbol _POSIX_THREAD_ATTR_STACKSIZE, then you can set the stacksize attribute to specify the minimum size for the stack of a thread created using the attributes object. Most systems will support this option, but you should use it with caution because stack size isn't portable. The amount of stack space you'll need depends on the calling standards and data formats used by each system.
Pthreads defines the symbol PTHREAD_STACK_MIN as the minimum stack size required for a thread: If you really need to specify a stack size, you might be best off calculating your requirements in terms of the minimum required by the implementation. Or, you could base your requirements on the default stacksize attribute selected by the implementation — for example, twice the default, or half the default. The program thread_attr.c shows how to read the default stacksize attribute value of an initialized attribute by calling pthread_attr_getstacksize
.
Setting the address of a stack is less portable!
If your system defines the symbol _POSIX_THREAD_ATTR_STACKADDR, then you can set the stackaddr attribute to specify a region of memory to be used as a stack by any thread created using this attributes object. The stack must be at least as large as PTHREAD_STACK_MIN. You may need to specify an area of memory with an address that's aligned to some required granularity. On a machine where the stack grows downward from higher addresses to lower addresses, the address you specify should be the highest address in the stack, not the lowest. If the stack grows up, you need to specify the lowest address.
You also need to be aware of whether the machine increments (or decrements) the stack before or after writing a new value — this determines whether the address you specify should be "inside" or "outside" the stack you've allocated. The system can't tell whether you allocated enough space, or specified the right address, so it has to trust you. If you get it wrong, undesirable things will occur.
Use the stackaddr attribute only with great caution, and beware that it may well be the least portable aspect of Pthreads. While a reasonable value for the stacksize attribute will probably work on a wide range of machines, it is little more than a wild coincidence if any particular value of the stackaddr attribute works on any two machines. Also, you must remember that you can create only one thread with any value of the stackaddr attribute. If you create two concurrent threads with the same stackaddr attribute value, the threads will run on the same stack. (That would be bad.)
The thread_attr.c program that follows shows some of these attributes in action, with proper conditionalization to avoid using the stacksize attribute if it is not supported by your system. If stacksize is supported (and it will be on most UNIX systems), the program will print the default and minimum stack size, and set stacksize to a value twice the minimum. The code also creates the thread detached, which means no thread can join with it to determine when it completes. Instead, main exits by calling pthread_exit
, which means that the process will terminate when the last thread exits.
This example does not include the priority scheduling attributes, which are discussed (and demonstrated) in Section 5.5.2. It also does not demonstrate use of the stackaddr attribute — as I said, there is no way to use stackaddr in any remotely portable way and, although I have mentioned it for completeness, I strongly discourage use of stackaddr in any program.
? thread_attr.c
1 #include <limits.h>
2 #include <pthread.h>
3 #include "errors.h"
4
5 /*
6 * Thread start routine that reports it ran, and then exits.
7 */
8 void *thread_routine (void *arg)
9 {
10 printf ("The thread is heren");
11 return NULL;
12 }
13
14 int main (int argc, char *argv[])
15 {
16 pthread_t thread_id;
17 pthread_attr_t thread_attr;
18 struct sched_param thread_param;
19 size_t stack_size;
20 int status;
21
22 status = pthread_attr_init (&thread_attr);
23 if (status != 0)
24 err_abort (status, "Create attr");
25
26 /*
27 * Create a detached thread.
28 */
29 status = pthread_attr_setdetachstate (
30 &thread_attr, PTHREAD_CREATE_DETACHED);
31 if (status != 0)
32 err_abort (status, "Set detach");
33 #ifdef _POSIX_THREAD_ATTR_STACKSIZE
34 /*
35 * If supported, determine the default stack size and report
36 * it, and then select a stack size for the new thread.
37 *
38 * Note that the standard does not specify the default stack
39 * size, and the default value in an attributes object need
40 * not be the size that will actually be used. Solaris 2.5
41 * uses a value of 0 to indicate the default.
42 */
43 status = pthread_attr_getstacksize (&thread_attr, &stack_size);
44 if (status != 0)
45 err_abort (status, "Get stack size");
46 printf ("Default stack size is %u; minimum is %un",
47 stack_size, PTHREAD_STACK_MIN);
48 status = pthread_attr_setstacksize (
49 &thread_attr, PTHREAD_STACK_MIN*2);
50 if (status != 0)
51 err_abort (status, "Set stack size");
52 #endif
53 status = pthread_create (
54 &thread_id, &thread_attr, thread_routine, NULL);
55 if (status != 0)
56 err_abort (status, "Create thread");
57 printf ("Main exitingn");
58 pthread_exit (NULL);
59 return 0;
60 }