Книга: Distributed operating systems
10.2.4. Thread Calls
10.2.4. Thread Calls
The DCE threads package has a total of 54 primitives (library procedures). Many of these are not strictly necessary but are provided for convenience only. This approach is somewhat analogous to a four-function pocket calculator that has keys not only for +, –, ?, and /, but also has keys for +1, –1, ?2, ?10, ??, /2, and /10, on the grounds that these save the user time and effort. Due to the large number of calls, we will discuss only the most important ones (about half the total). Nevertheless, our treatment should give a reasonable impression of the available functionality.
Call | Description |
---|---|
Create | Create a new thread |
Exit | Called by a thread when it is finished |
Join | Like the WAIT system call in UNIX |
Detach | Make it unnecessary for parent thread to wait when caller exits |
Fig. 10-6. Selected DCE thread calls for managing threads. All the calls in this section are actually prefixed by pthread_ (i.e., pthread_create, not create), which we have omitted to save space.
For our discussion, it is convenient to group the calls into seven categories, each dealing with a different aspect of threads and their use. The first category, listed in Fig. 10-6, deals with thread management. These calls allow threads to be created and for them to exit when done. A parent thread can wait for a child using join, which is similar to the WAIT system call in UNIX. If a parent has no interest in a child and does not plan to wait for it, the parent can disown the child by calling detach. In this case, when the child thread exits, its storage is reclaimed immediately instead of having it wait for the parent to call join.
The DCE package allows the user to create, destroy, and manage templates for threads, mutexes, and condition variables. The templates can be set up to have appropriate initial values. When an object is created, one of the parameters to the create call is a pointer to a template. For example, a thread template can be created and given the attribute (property) that the stack size is 4K. Whenever a thread is created with that template as parameter, it will get an 4K stack. The point of having templates is to eliminate the need for specifying all the options as separate parameters. As the package evolves, the create calls can remain the same. Instead, new attributes can be added to the templates. Some of the template calls are listed in Fig. 10-7.
Call | Description |
---|---|
Attr_create | Create template for setting thread parameters |
Attr_delete | Delete template for threads |
Attr_setprio | Set the default scheduling priority in the template |
Attr_getprio | Read the default scheduling priority from the template |
Attr_setstacksize | Set the default stack size in the template |
Attr_getstacksize | Read the default stack size from the template |
Attr_mutexattr_create | Create template for mutex parameters |
Attr_mutexattr_delete | Delete template for mutexes |
Attr_mutexattr_setkind_np | Set the default mutex type in the template |
Attr_mutexattr_getkind_np | Read the default mutex type from the template |
Attr_condattr_create | Create template for condition variable parameters |
Attr_condattr_delete | Delete template for condition variables |
Fig. 10-7. Selected template calls.
The attr_create and attr_delete calls create and delete thread templates, respectively. Other calls allow programs to read and write the template's attributes, such as the stack size and scheduling parameters to be used for threads created with the template. Similarly, calls are provided to create and delete templates for mutexes and condition variables. The need for the latter is not entirely obvious, since they have no attributes and no operations. Perhaps, the designers were hoping that someone would one day think of an attribute.
The third group deals with mutexes, which can be created and destroyed dynamically. Three operations are defined on mutexes, as shown in Fig. 10-8. The operations are for locking, unlocking mutexes, and for trying but accepting failure if locking cannot be done.
Call | Description |
---|---|
Mutex_init | Create a mutex |
Mutex_destroy | Delete a mutex |
Mutex_lock | Try to lock a mutex; if it is already locked, block |
Mutex_trylock | Try to lock a mutex; fail if it is already locked |
Mutex_unlock | Unlock a mutex |
Fig. 10-8. Selected mutex calls.
Next come the calls relating to condition variables, listed in Fig. 10-9. Condition variables, too, can be created and destroyed dynamically. Threads can sleep on condition variables pending the availability of some needed resource. Two wakeup operations are provided: signaling, which wakes up exactly one waiting thread, and broadcasting, which wakes them all up.
Call | Description |
---|---|
Cond_init | Create a condition variable |
Cond_destroy | Delete a condition variable |
Cond_wait | Wait on a condition variable until a signal or broadcast arrives |
Cond_signal | Wake up at most one thread waiting on the condition variable |
Cond_broadcast | Wake up all the threads waiting on the condition variable |
Fig. 10-9. Selected condition variable calls.
Figure 10-10 lists the three calls for manipulating per-thread global variables. These are variables that may be used by any procedure in the thread that created them, but which are invisible to other threads. The concept of a per-thread global variable is not supported by any of the popular programming languages, so they have to be managed at run time. The first call creates an identifier and allocates storage, the second assigns a pointer to a per-thread global variable, and the third allows the thread to read back a per-thread global variable value. Many computer scientists consider global variables to be in the same league as that all-time great pariah, the GOTO statement, so they would no doubt rejoice at the idea of making them cumbersome to use. (The author once tried to design a programming language with a
IKNOWTHISISASTUPIDTHINGTODOBUTNEVERTHELESSGOTO LABEL;
statement, but was forcibly restrained from doing so by his colleagues.) It can be argued that having per-thread global variables use procedure calls instead of language scoping rules, like locals and globals, is an emergency measure introduced simply because most programming languages do not allow the concept to be expressed syntactically.
Call | Description |
---|---|
Keycreate | Create a global variable for this thread |
Setspecific | Assign a pointer value to a per-thred global variable |
Getspecific | Read a pointer value from a per-thread global variable |
Fig. 10-10. Selected per-thread global variable calls.
The next group of calls (see Fig. 10-11) deals with killing threads and the threads' ability to resist. The cancel call tries to kill a thread, but sometimes killing a thread can have devastating effects, for example, if the thread has a mutex locked at the time. For this reason, threads can arrange for attempts to kill them to be enabled or disabled in various ways, very roughly analogous to the ability of UNIX processes to catch or ignore signals instead of being terminated by them.
Call | Description |
---|---|
Cancel | Try to kill another thread |
Setcancel | Enable or disable ability of other threads to kill this thread |
Fig. 10-11. Selected calls relating to killing threads.
Finally, our last group (see Fig. 10-12) is concerned with scheduling. The package allows the threads in a process to be scheduled according to FIFO, round robin, preemptive, nonpreemptive, and other algorithms. By using these calls, the algorithm and priorities can be set. The system works best if threads do not elect to be scheduled with conflicting algorithms.
Call | Description |
---|---|
Setscheduler | Set the scheduling algorithm |
Getscheduler | Read the current scheduling algorithm |
Setprio | Set the scheduling priority |
Getprio | Get the current scheduling priority |
Fig. 10-12. Selected scheduling calls.
- 5.5. The init Thread
- 4.1.2. Thread Usage
- 4.1.3. Design Issues for Threads Packages
- 4.1.4. Implementing a Threads Package
- 8.2.2. Threads
- 9.2.2. Threads
- 6.6.5 SIGEV_THREAD
- 4 A few ways to use threads
- Функция pthread_rwlock_trywrlock
- Thread resources on the Internet
- 5.5.1. Initialization via initcalls
- 15.4.2. Debugging Multithreaded Applications