線程

線程（thread）在電腦科學中，是將進程劃分為兩個或多個線程（實例）或子進程，由單處理器（單線程）或多處理器（多線程）或多核處理系統並發執行。

## 狀態

執行緒有四種基本狀態，分別為：

- 產生（spawn）
- 阻塞（block）
- 非阻塞（unblock）
- 結束（finish）

## 線程包含要素

- 線程內核對象(thread kernel object)
- 線程環境塊(thread environment block, TEB)
- 使用者模式棧(user-mode stack)（unblock）
- 內核模式棧(kernal-mode stack)(thread environment block, TEB)
- DLL線程連接(attach)和線程分離(detach)通知(kernal-mode stack)

## 不同平台的線程

### UNIX International線程

#### UNIX International線程簡介

SUN Solaris作業系統使用的線程叫做UNIX International線程，支持內核線程、輕權進程和使用者線程。一個進程可有大量使用者線程；大量使用者線程復用少量的輕權進程，輕權進程與內核線程一一對應。使用者級線程在調用核心服務時（如文件讀寫），需要「捆綁（bound）」在一個LWP上。永久捆綁（一個LWP固定被一個使用者級線程占用，該LWP移到LWP池之外）和臨時捆綁（從LWP池中臨時分配一個未被占用的LWP）。在調用系統服務時，如果所有LWP已被其他使用者級線程所占用（捆綁），則該線程阻塞直到有可用的LWP。如果LWP執行系統線程時阻塞（如`read()`調用），則當前捆綁在LWP上的使用者級線程也阻塞。

#### UNIX International線程的有關API

UNIX International線程的頭文件是`<thread.h>`。

##### 創建使用者級線程

```c
int thr_create(void * stack_base, size_t stack_size, void *(*start_routine，void *), void * arg, long flags, thread_t * new_thr);
```

其中flags包括：THR_BOUND（永久捆綁）, THR_NEW_LWP（創建新LWP放入LWP池），若兩者同時指定則創建兩個新LWP，一個永久捆綁而另一個放入LWP池。

##### 等待使用者級線程

```c
int thr_join(thread_t wait_for, thread_t *dead, void **status);
```

##### 掛起使用者級線程

```c
int thr_suspend(thread_t thr);
```

##### 繼續使用者級線程

```c
int thr_continue(thread_t thr);
```

##### 退出使用者級線程

```c
void thr_exit(void *status);
```

##### 返回當前使用者級線程的線程標識符

```c
thread_t thr_self( void );
```

### POSIX線程

#### POSIX線程簡介

POSIX線程（POSIX threads），簡稱Pthreads，是線程的POSIX標準。該標準定義了創建和操縱線程的一整套API。在類Unix作業系統（Unix、Linux、Mac OS X等）中，都使用Pthreads作為作業系統的線程。Windows作業系統也有其移植版pthreads-win32。

#### POSIX線程的有關API

Pthreads線程的頭文件是`<pthread.h>`。

##### 創建使用者線程

```c
int pthread_create(pthread_t * thread, const pthread_attr_t * attr, void *(*start_routine)(void *), void *arg);
```

##### 等待使用者線程

```c
int pthread_join(pthread_t thread, void ** retval);
```

##### 退出使用者線程

```c
void pthread_exit(void *retval);
```

##### 返回當前使用者線程的線程標識符

```c
pthread_t pthread_self(void);
```

##### 使用者線程的取消

```c
int pthread_cancel(pthread_t thread);
```

### Win32線程

#### Win32線程簡介

Win32線程是Windows API的一部分，上下文包括：寄存器、核心棧、線程環境塊和使用者棧。

#### Win32線程的有關API

Win32線程的頭文件是`<Windows.h>`，僅適用於Windows作業系統。

##### 創建使用者線程

```c
HANDLE WINAPI CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId);
```

##### 結束本線程

```c
VOID WINAPI ExitThread(DWORD dwExitCode);
```

##### 掛起指定的線程

```c
DWORD WINAPI SuspendThread( HANDLE hThread );
```

##### 恢復指定線程運行

```c
DWORD WINAPI ResumeThread(HANDLE hThread);
```

##### 等待線程運行完畢

```c
DWORD WINAPI WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds);
```

##### 返回當前線程的線程標識符

```c
DWORD WINAPI GetCurrentThreadId(void);
```

##### 返回當前線程的線程句柄

```c
HANDLE WINAPI GetCurrentThread(void);
```

## 跨平台的線程

### C++11線程

#### C++11線程簡介

2011年8月12日，國際標準化組織（ISO）發布了第三個C++標準，即ISO/IEC 14882:2011，簡稱ISO C++ 11標準。該標準第一次把線程的概念引入C++標準庫。Windows平台運行的VS2012和Linux平台運行的g++4.7，都完美支持C++11線程。

#### C++11線程的有關函數

C++ 11線程的頭文件是`<thread>`。

##### 創建線程

```cpp
std::thread::thread(Function&& f, Args&&... args);
```

##### 等待線程結束

```cpp
std::thread::join();
```

##### 脫離線程控制

```cpp
std::thread::detach();
```

##### 交換線程

```cpp
std::thread::swap(thread& other);
```

### C11線程

#### C11線程簡介

2011年12月8日，國際標準化組織（ISO）發布了第三個C語言標準，即ISO 9899:2011，簡稱ISO C 11標準。該標準第一次把線程的概念引入C語言標準庫。

C11線程僅僅是個「建議標準」，也就是說100%遵守C11標準的C編譯器是可以不支持C11線程的。根據C11標準的規定，只要編譯器預定義了 __STDC_NO_THREADS__(C11)，就可以沒有`<threads.h>`頭文件，自然也就也沒有下列函數。

#### C11線程的有關函數

C11線程的頭文件是`<threads.h>`。

##### 創建線程

```c
int thrd_create(thrd_t *thr, thrd_start_t func, void *arg);
```

##### 結束本線程

```c
_Noreturn void thrd_exit( int res );
```

##### 等待線程運行完畢

```c
int thrd_join(thrd_t thr, int *res);
```

##### 返回當前線程的線程標識符

```c
thrd_t thrd_current();
```

### Java線程

- 最簡單的情況是，Thread/Runnable的`run()`方法運行完畢，自行終止。
- 對於更複雜的情況，比如有循環，則可以增加終止標記變量和任務終止的檢查點。
- 最常見的情況，也是為了解決阻塞不能執行檢查點的問題，用中斷來結束線程，但中斷只是請求，並不能完全保證線程被終止，需要執行線程協同處理。
- IO阻塞和等鎖情況下需要通過特殊方式進行處理。
- 使用Future類的`cancel()`方法調用。
- 調用線程池執行器的`shutdown()`和`shutdownNow()`方法。
- 守護線程會在非守護線程都結束時自動終止。
- Thread有`stop()`方法，但已不推薦使用。