介紹
在現代操作系統中,每個進程都有自己的地址空間和一個控制線程。然而,在實踐中,我們經常面臨需要在單個進程中執行多個并發任務并訪問相同流程組件的情況:結構、打開文件描述符等。
在任何情況下組織多線程模型都需要同時訪問相同的資源。本文提供有關 Windows 和 Linux 操作系統中線程的一般信息,然后介紹同步機制[1]阻止訪問共享資源。
對于那些處理從一個系統移植到另一個系統的應用程序,或者在一個系統中創建多線程應用程序并想知道它在另一個系統中的實際實現方式的人來說,本文將很有趣。對于那些從未使用多個線程編寫應用程序但計劃在未來這樣做的人,本文也將很有用。
螺紋概念
這些線程需要做什么?為什么我們不能只創建流程?后一種范式已經工作了很多年,但流程創建有一些缺點,只有以下幾個例子:
流程創建操作是資源密集型操作。
進程需要復雜的機制來訪問相同的資源(命名或未命名管道、消息隊列、套接字等),而線程會自動訪問相同的地址空間。
多線程進程的性能高于單線程進程。
多線程允許多個線程作為一個進程的一部分執行。帶有線程的編程模型為開發人員提供了同時執行的舒適抽象。帶線程的程序的優點之一是它在具有多核處理器的計算機上運行得更快。線程在創建時幾乎不使用資源,也不使用資源訪問機制等其他插件;此外,線程的性能和應用程序交互性更高。除了地址空間,所有線程都使用:
工藝規定
信號處理程序(用于處理信號的設置)
當前目錄
用戶和組標識符
同時,每個線程都有自己的:
線程標識符
疊
寄存器集
信號掩模
優先權
使用線程的主要函數
在通過 exec 調用啟動程序時,將創建一個主線程(初始線程)。輔助線程是通過調用 Linux 的 pthread_create 或 Windows 的 _beginthread(ex) 來創建的。
讓我們更仔細地看一下 Linux 的線程創建:
#include
int pthread_create(
pthread_t *tid,
const pthread_attr_t *attr,
void *(*func)(void *),
void *arg
);
/* 成功完成時返回 0,出錯時返回正值*/
每個線程都有其標識符 –pthread_t– 和屬性:優先級、初始堆棧大小、守護程序功能。創建線程時,必須指示將執行的函數地址 (func) 以及單指針參數 (arg)。Linux 中的線程應顯式退出 –pthread_exit通過調用函數 – 或間接退出 – 通過從該函數返回[2]。如果在問題條件下需要將多個參數傳遞給線程,則必須將結構的地址與參數一起使用。
在Windows中,線程是在_beginthread(ex)或CreateThread函數的幫助下創建的。兩者都是運行時調用,它們之間的主要區別在于 CreateThread 是一個“原始”Win32 API,并且_beginthread(ex)反過來調用自身內部的CreateThread。在本文中,我們將討論_beginthread(ex)函數。_beginthreadex的語法如下:
uintptr_t _beginthreadex(
void *security,
unsigned stack_size,
unsigned(__stdcall *start_address)(void *),
void *arglist,
unsigned initflag,
unsigned *thrdaddr
);
可以觀察到,在pthread_create和_beginthreadex調用之間有一些模糊的相似之處;但是,也存在差異。?hus, in Windows:security– 指向結構的指針SECURITY_ATTRIBUTES,thrdaddr– 指向接收線程標識符的 32 位變量。
讓我們考慮以下線程創建示例[3]:
#include
#ifdef __PL_WINDOWS__
#include
#endif //__PL_WINDOWS__
#ifdef __PL_LINUX__
#include
#endif //__PL_LINUX__
#define STACK_SIZE_IN_BYTES (2097152) //2MB
#ifdef __PL_WINDOWS__
unsigned int __stdcall process_command_thread(void) {
#endif //__PL_WINDOWS__
#if defined (__PL_LINUX__) || (__PL_SOLARIS__) || (__PL_MACOSX__)
void *process_command_thread(void *p) {
#endif //(__PL_LINUX__) || (__PL_SOLARIS__) || (__PL_MACOSX__)
printf(“Hello from process command threadn”);
return 0;
}
int main(int argc, char *argv[])
{
#ifdef __PL_WINDOWS__
DWORD process_command_thread_id;
HANDLE h_process_command_thread;
h_process_command_thread = (HANDLE)_beginthreadex(
NULL,
STACK_SIZE_IN_BYTES,
process_command_thread,
NULL,
0,
(unsigned long *)&process_command_thread_id
);
if (h_process_command_thread == NULL)
return -1;
#endif //__PL_WINDOWS__
#ifdef __PL_LINUX__
pthread_t h_process_command_thread;
int h_process_command_thread_initialized;
int ret;
ret = pthread_create(
&h_process_command_thread,
NULL,
process_command_thread,
NULL
);
if (ret != 0)
return -1;
h_process_command_thread_initialized = 1;
#endif // __PL_LINUX__
printf(“Hello from main threadn”);
return 0;
}
輸出將如下所示:
Linux目錄窗戶
[root@localhost~]# 。/進程
來自主線程的你好
[root@localhost ~]#C:》進程.exe
來自主線程的你好
C:》
很容易注意到process_command_thread不是以可視方式運行的。當用于線程管理的內部結構由pthread_createor_beginthreadex函數初始化時,主線程完成執行。我們可以預期在為 Linux 調用pthread_join后線程退出。
int pthread_join(pthread_t tid, void **retval);
線程可以是可連接的(默認情況下)或分離的。當可連接線程終止時,信息(標識符、終止狀態、線程計數器等)將保留,直到調用pthread_join。
在Windows操作系統中,其中一個等待功能可能被視為類似于pthread_join。等待函數系列允許線程中斷其執行并等待資源釋放。讓我們看一下pthread_join的類似物,即WaitForSingleObject:
DWORD WaitForSingleObject(HANDLE hObject, DWORD dwMilliseconds);
調用此函數時,第一個參數 hObject 標識內核對象。此對象可能處于以下兩種狀態之一:“空閑”或“忙碌”。
第二個參數 dwMilliseconds 指示線程準備好等待釋放對象的毫秒數。
以下示例說明了pthread_joinWaitForSingleObject調用:
#ifdef __PL_WINDOWS__
DWORD status = WaitForSingleObject(
h_process_command_thread,
INFINITE
);
switch (status) {
case WAIT_OBJECT_0:
// The process terminated
break;
case WAIT_TIMEOUT:
// The process did not terminate within timeout
break;
case WAIT_FAILED:
// Bad call to function
break;
}
#endif //__PL_WINDOWS__
#ifdef __PL_LINUX__
int status = pthread_join(
h_process_command_thread,
NULL
);
switch (status) {
case 0:
// The process terminated
break;
case default:
// Bad call to function
break;
}
#endif //__PL_LINUX__
#ifdef __PL_WINDOWS__
//Windows code
#endif //__PL_WINDOWS__
#ifdef __PL_LINUX__
//Code for UNIX OS systems
#endif //__PL_LINUX__
對于 Linux,本文介紹了由 POSIX.1-2001 標準(稱為“pthreads”)定義的線程接口。
本文稍后將介紹線程退出。
在此示例中,與本文中的其他示例一樣,Linux 和 Windows 的代碼庫都是單一的。區別在于編譯條件:
#ifdef __PL_WINDOWS__
//Windows code
#endif //__PL_WINDOWS__
#ifdef __PL_LINUX__
//Code for UNIX OS systems
#endif //__PL_LINUX__
-
Linux
+關注
關注
87文章
11296瀏覽量
209348 -
WINDOWS
+關注
關注
3文章
3541瀏覽量
88633
發布評論請先 登錄
相關推薦
評論