Книга: Programming with POSIX® Threads

1.9.3 Checking for errors

1.9.3 Checking for errors

Pthreads introduces a new way to report errors,without using the errno variable.

The Pthreads amendment is the first part of POSIX to depart from the ancient UNIX and C language conventions regarding error status. Traditionally, functions that succeed returned a useful value if appropriate, or otherwise indicated success by returning the value 0. On failure, they returned the special value -1, and set the global value errno to a code specifying the type of error.

The old mechanism has a number of problems, including the fact that it is difficult to create a function that can both report an error and return a useful value of -1. There are even worse problems when you add multiple threads to a process. In traditional UNIX systems, and in the original POSIX.l-1990 standard, errno was an extern int variable. Since such a variable can have only one value at a time, it can support only a single stream of execution within the process.

Pthreads functions don't set errno on errors! (But most other POSIX functions do.)

New functions in the Pthreads standard reserve the return value for error status, and errno is not used. Pthreads functions return the value 0 on success, and include an extra output parameter to specify an address where "useful results" are stored. When a function cannot complete successfully, an error code from the <errno.h> header file is returned instead of 0 as the function value.

Pthreads also provides a per-thread errno, which supports other code that uses errno. This means that when one thread calls some function that reports an error using errno, the value cannot be overwritten, or read, by any other thread— you may go on using errno just as you always have. But if you're designing new interfaces you should consider following the new Pthreads convention for reporting errors. Setting or reading the per-thread errno involves more overhead than reading or writing a memory location, or returning a value from a function.

To wait for a thread, for example, and check for an error, you might use code like that shown in the following code example, thread_error.c. The pthread_join function, used to wait for a thread to terminate, will report an invalid thread identifier by returning the error code ESRCH. An uninitialized pthread_t is likely to be an invalid thread identifier on most implementations. The result of running this program should be a message such as "error 3: no such process."

In the unlikely event that the uninitialized thread variable has a pthread_t value that is not invalid, it should be the ID of the initial thread (there are no other threads in this process). In this case, pthread_join should either fail with EDEADLK, if your implementation of Pthreads detects self-deadlock, or the thread will hang waiting for itself to exit.

? thread_error.c

1 #include <pthread.h>
2 #include <stdio.h>
3 #include <errno.h> 4
5 int main (int argc, char *argv[])
6 {
7 pthread_t thread;
8 int status;
9
10 /*
11 * Attempt to join with an uninitialized thread ID. On most
12 * implementations, this will return an ESRCH error code. If
13 * the local (and uninitialized) pthread_t happens to be a valid
14 * thread ID, it is almost certainly that of the initial thread,
15 * which is running main(). In that case, your Pthreads
16 * implementation may either return EDEADLK (self-deadlock),
17 * or it may hang. If it hangs, quit and try again. */
18 */
19 status = pthread_join (thread, NULL);
20 if (status != 0)
21  fprintf (stderr, "error %d: %sn", status, strerror (status));

22 return status;
23 }

Note that there is no equivalent to the perror function to format and print an error value returned by the Pthreads interfaces. Instead, use strerror to get a string description of the error number, and print the string to the file stream stderr.

To avoid cluttering each function call in the example programs with a block of code to report each error and call abort, I have built two error macros—err_abort detects a standard Pthreads error, and errno_abort is used when a value of -1 means that errno contains an error code. The following header file, called errors.h, shows these macros. The errors.h header file also includes several system header files, which would otherwise be required by most of the example programs—this helps to reduce the size of the examples.

errors.h

1 #ifndef _errors_h
2 #define _errors_h
3
4 #include <unistd.h>
5 #include <errno.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>

9
10 /*
11 * Define a macro that can be used for diagnostic output from
12 * examples. When compiled -DDEBUG, it results in calling printf
13 * with the specified argument list. When DEBUG is not defined, it
14 * expands to nothing.
15 */
16 #ifdef DEBUG
17 # define DPRINTF(arg) printf arg
18 #else
19 # define DPRINTF(arg)
20 #endif

21
22 /*
23 * NOTE: the "do {" ... "} while (0);" bracketing around the macros
24 * allows the err_abort and errno_abort macros to be used as if they
25 * were function calls, even in contexts where a trailing ";" would
26 * generate a null statement. For example,
27 *
28 * if (status != 0)
29 * err_abort (status, "message");
30 * else
31 * return status;
32 *
33 * will not compile if err_abort is a macro ending with "}", because
34 * C does not expect a ";" to follow the "}". Because C does expect
35 * a ";" following the ")" in the do...while construct, err_abort and
36 * errno_abort can be used as if they were function calls.
37 */
38 #define err_abort(code,text) do {
39  fprintf (stderr, "%s at "%s":%d: %sn",
40  text, _FILE_, _LINE_, strerror (code));
41  abort ();
42 } while (0)
43 #define errno_abort(text) do {
44  fprintf (stderr, "%s at "%s":%d: %sn",
45  text, _FILE_, _LINE_, strerror (errno));
46  abort ( );
47 } while (0)

48
49 #endif

The one exception to the Pthreads error rules is pthread_getspecific, which returns the thread-specific data value of a shared "key." Section 5.4 describes thread-specific data in detail, but for now we're just concerned with error reporting. The capability of managing thread-specific data is critical to many applications, and the function has to be as fast as possible, so the pthread_ getspecific function doesn't report errors at all. If the pthread_key_t value is illegal, or if no value has been set in the thread, pthread_getspecific just returns the value NULL.

Оглавление книги


Генерация: 1.154. Запросов К БД/Cache: 3 / 0
поделиться
Вверх Вниз