1. Threading is the creation and management of
multiple units of execution within a single process
二進制文件是駐留在存儲介質上,已被編譯成操做系統可使用,準備執行但沒有正運行的
休眠程序
進程是操做系統對
正在執行中的二進制文件的抽象:已加載的二進制、虛擬內存、內核資源
線程是進程內的執行單元
processes are running binaries, threads are the smallest unit of execution schedulable by an operating system's process scheduler
現代操做系統爲用戶級程序提供了最基礎的虛擬化抽象:
虛擬內存和虛擬處理器,這就形成一種假象,彷佛每一個運行進程都獨佔系統資源
Virtualized memory affords each process a unique view of memory
A virtualized processor lets processes act as if they alone run on the system
虛擬內存是與進程相關聯的,不是線程。每一個進程都有惟一的內存映像,可是進程內的全部線程是共享該進程的地址空間
虛擬處理器是與線程相關聯的,不是進程。每一個線程都是可調度的獨立實體。
2. 多線程
多線程有如下好處:
(1) 編程抽象:thread-per-connection and thread pool patterns
(2) 並行:
每一個線程都有專屬的虛擬處理器而且是獨立的可調度實體,這能夠提升系統吞吐量
(3) 提升響應能力:多線程中,相似用戶輸入的操做能夠委託給一個工做線程,容許至少一個線程對用戶輸入和GUI操做保持響應
(4) 阻塞I/O:多線程中,單個線程阻塞,其它線程仍然能夠繼續執行。
多路I/O和非阻塞I/O也是可供選擇的解決單進程阻塞I/O問題的方案
(5) 上下文交換:線程的上下文交換代價遠小於進程
(6) 節省內存:線程是共享進程的地址空間,可充分節省內存
Failing to synchronize threads can lead to corrupt output, incorrect execution, and program crash.
Understanding and debugging multithreaded programs is so difficult
3. 線程模型
(1) Thread-per-Connection
a unit of work is assigned to one thread, and that thread is assigned at most one unit of work, for the duration of the unit of work's execution
在這個模型中,線程數量是一個實現細節,
大多數實現對線程的建立數量設有一個上限,當鏈接數(也就是線程數) 達到上限值時,更多的鏈接會排隊或者被拒絕知道鏈接數降至上限值如下
(2) Event-Driven Threading
most of the threads are doing a lot of waiting,
using more threads than you have processors on the system does not provide any benefits to parallelism
由於在 Thread-per-Connection中,
負載一般在於I/O等待,咱們將此等待過程從線程中解耦出來。在這種模式中,請求處理過程與一系列回調函數相關聯,這些回調函數能夠經過 多路I/O(select、epoll)來等待I/O,這種模式成爲 event loop,When the I/O requests are returned, the event loop hands the callback off to a waiting thread
4. 併發、並行、競爭
Concurrency is the ability of two or more threads to execute in overlapping
time periods
Parallelism is the ability to execute two or more threads
simultaneously
Concurrency can occur without parallelism: for example, multitasking on a single processor system
With parallelism, threads literally execute in parallel
By enabling overlapping execution, threads can execute in an unpredictable order with respect to each other
A race condition is a situation in which the unsynchronized access of a shared resource by two or more threads leads to erroneous program behavior.
臨界區:the region of code which should be synchronized
it takes the current value of x, increments it by one, and stores that new value back in x
這個例子說明了併發的狀況,若是是並行,則狀況以下:程序員
5. 同步
爲了防止競爭條件,程序員必須同步訪問臨界區,即確保互斥訪問臨界區
There are many techniques for making critical regions atomic,The most common technique is the lock
A deadlock is a situation in which two threads are waiting for the other to finish, and thus neither does
In the case of mutexes,
a deadlock occurs where two threads are each waiting for a different mutex, which the other thread holds,
known as the ABBA deadlock
Because each thread that holds a mutex is also waiting for a mutex, neither is ever released, and the threads deadlock
6. Pthread
(1) Creating Threads
#include <pthread.h>
int pthread_create (pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
一旦調用成功,新線程被建立,開始執行start_routine回調函數,arg就是此回調函數的輸入參數
pthread_attr_t改變新建線程的默認屬性,例如棧大小、調度參數等,
通常爲NULL,表示默認線程屬性
the new thread inherits most attributes, capabilities, and state from its parent
(2) Thread IDs
POSIX does not require it to be an arithmetic type, 注意 線程ID不必定就是整型數,爲了移植性,因此用 pthread_t
const pthread_t me = pthread_self ();
int pthread_equal (pthread_t t1, pthread_t t2);
(3) Terminating Threads
線程終止有如下幾種可能:
a. returns from its start routine, it terminates,相似於進程的執行到main函數末尾
b. 調用pthread_exit(),相似於進程的 exit()
c. 被其它線程經過 pthread_cancel() 終止,相似於 進程的 接收到
SIGKILL signal via kill()
#include <pthread.h>
int pthread_cancel (pthread_t thread);
pthread_cancel() sends a cancellation request to the thread represented by the thread ID thread.
(4) Joining and Detaching Threads
Joining allows one thread to block while waiting for the termination of another
#include <pthread.h>
int pthread_join (pthread_t thread, void **retval);
調用線程被阻塞,直到指定線程終止
All threads in Pthreads are peers; any thread may join any other
int ret;
/* join with `thread' and we don't care about its return value */
ret = pthread_join (thread, NULL);
if (ret) {
errno = ret;
perror ("pthread_join");
return -1;
}
分離線程:
默認狀況下,新建線程是可結合的
#include <pthread.h>
int pthread_detach (pthread_t thread);
綜合示例:編程
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
void * start_thread (void *message)
{
printf ("%s\n", (const char *) message);
return message;
}
int main (void)
{
pthread_t thing1, thing2;
const char *message1 = "Thing 1";
const char *message2 = "Thing 2";
/* Create two threads, each with a different message. */
pthread_create (&thing1, NULL, start_thread, (void *) message1);
pthread_create (&thing2, NULL, start_thread, (void *) message2);
/*
* Wait for the threads to exit. If we didn't join here,
* we'd risk terminating this main thread before the
* other two threads finished.
*/
pthread_join (thing1, NULL);
pthread_join (thing2, NULL);
return 0;
}
gcc -Wall -O2 -pthread example.c -o example
輸出結果:
Thing 1 或者 Thing 2
Thing 2 Thing 1
(5) 初始化鎖
/* define and initialize a mutex named `mutex' */
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
(6) 加鎖、解鎖多線程
int pthread_mutex_lock (pthread_mutex_t *mutex);
int pthread_mutex_unlock (pthread_mutex_t *mutex);
Resource Acquisition Is Initialization (RAII) is a C++ programming pattern
Using RAII to acquires a mutex on creation and automatically releases the mutex when it falls out of scope
class ScopedMutex {
public:
ScopedMutex (pthread_mutex_t& mutex)
:mutex_ (mutex)
{
pthread_mutex_lock (&mutex_);
}
~ScopedMutex ()
{
pthread_mutex_unlock (&mutex_);
}
private:
pthread_mutex_t& mutex_;
};