APUE - POSIX Threads

Preface

This article contains large scale extraction from APUE (3ed). I will not put this article into commercial use.

Why Threading

Simpler Programming Model

A synchronous programming model is much simpler than an asynchronous programming model.

Easier Access to Resources

Multiple processes have to use complex mechanisms provided by the OS to share memory and file descriptors. Threads, in contrast, automatically have access to the same memory address space and file descriptors.

Recall: Almost every multi-process programming involves fork(). fork() duplicates memory space and file descriptors instead of sharing them.

Improved Information Throughput

Some problems can be partitioned so that overall program throughput can be improved. With multiple threads of control, the processing of independent tasks can be interleaved by assigning a separate thread per task.

Two tasks can be interleaved only if they don’t depend on the processing performed by each other.

Improved Response Time

Interactive programs can realize improved response time by using multiple threads to separate the portions of the programming that deal with user input and output from the other parts of the program.

NOTE: The benefits of a multithreaded programming model can be realized on a uniprocessor, or on multiprocessors/multicores.
1. Regardless of the number of processors, a program can be simplified.
2. As long as your program has to block when serializing tasks, you can still see improvements in response time and throughput when running on a uniprocessor, because some threads might be able to run while others are blocked.

Thread Information

What a thread consists

A thread consists of the information necessary to represent an execution context within a process:
1. thread ID
2. register values
3. stack
4. scheduling priority & policy
5. signal mask
6. errno variable
7. thread-specific data (中: 线程私有数据)

Thread ID

The thread ID has significance only within the context of the process to which it belongs.
Comparing thread IDs:

#include <pthread.h>
int pthread_equal(pthread_t tid1, pthread_t tid2);

Obtaining self thread ID:

#include <pthread.h>
int pthread_self();

Thread Creation

Additional threads can be created by calling the pthread_create function.

#include <pthread.h>
int pthread_create(pthread_t* tidp, 
                   const pthread_attr_t* attr
                   void* (*start_rtn)(void*),
                   void* arg);

NOTE:
1. The newly created thread starts running at the address of the function start_rtn.
2. If you need to pass more than one argument to start_rtn, then you first need to encapsulate them into a struct and pass its address;
3. There is no guarantee which will run first: the new one or the calling thread.
4. The newly created thread has access to the process address space, and inherits the calling thread’s floating-point environment and signal mask.
5. For the newly created thread, the set of pending signals is cleared.

What is a floating-point environment ?
浮点数环境
A floating-point environment is a set of floating-point states, which includes:
1. whether or not a thread can access the floating-point environment;
2. floating point exceptions(e.g. overflow, underflow, divide by zero, etc.)
3. rounding rules.

Thread Termination

Thread & exit

If any thread within a process calls exit, _Exit or _exit, the entire process terminates.
A single thread can exit in three ways without terminating the entire process:
1. Return: The thread can simply return from the start routine, whose return value is the thread’s exit code.
2. Cancelation: The thread can be canceled by another thread in the same process.
3. API: The thread can call pthread_exit.

How to fetch the exit code of a thread

First we need to know the pthread_join interface:

#include <pthread.h>
int pthread_join(pthread_t thread, void** rval_ptr);

The calling thread will block until the specified thread terminates in one of the three ways mentioned above.
Then we need to know how to set the exit code of a thread:
For example, by calling

pthread_exit((void*) 2);

you have the thread exit with exit code 2.
Finally we can study the following stereotype of fetching the exit code:

// This is the thread you are watching
pthread_t tid;
// This void* variable is used to store exit code
void* thread_return;

/*
 * Some business logic
 */

// The exit code of tid is written to thread_return
pthread_join(tid, &thread_return);

NOTE: It is not recommended to return the address of local variable as exit code. The chances are, the stack of other threads may reuse the stack of the thread just terminated, thus causing unsafe memory access.
See Figure 11-4 of APUE, 3rd edition

How to cancel a thread

One thread can request that another thread in the same process be canceled by calling the pthread_cancel function.

#include <pthread.h>
int pthread_cancel(pthread_t tid);

NOTE: pthread_cancel doesn’t wait for the thread to terminate; it merely makes the request.

How to clean up a thread

A thread can arrange for functions to be called when it exits, similar to the way that the atexit does for a process.

#include <pthread.h>
void pthread_cleanup_push(void(* rtn)(void*), void* arg);
void pthread_cleanup_pop(int execute);

The functions that passed to this function are known as thread cleanup handlers. More than one handler can be established for a thread. The handlers are recorded in a stack, which means that they are executed in the reverse order from that with which they were registered.
The cleanup handlers are called when the thread performs one of the following actions:
* Makes a call to pthread_exit
* Responds to a calcellation request
* Makes a call to pthread_cleanup_pop with a nonzero execute argument.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值