將應用程式從 OS/2 移植到 Linux 上: 第 1 部分,執行緒、互斥鎖、訊號量
級別: 初級
2004 年 4 月 01 日
Linux 是新千年裡最傑出的作業系統,而傳統的作業系統,如 OS/2,現在正在逐漸淘汰出局。本系列文章是為那些正經受移植痛苦的開發人員撰寫的,可以幫助他們將 OS/2 系統驅動和應用程式移植到 Linux 上。文中介紹瞭如何將各種 OS/2 呼叫一一對映到 Linux 上,涉及的內容包括執行緒、IPC、記憶體管理、定時器處理、檔案處理等。此外,文中還介紹了一些可以從 OS/2 對映到 Linux 上的前處理器指令和編譯器/連結器選項。本系列文章總共三篇,本文是其中的第一篇。
本文介紹了有關執行緒和同步原語對映方面的知識。本系列的後續文章將會介紹系統呼叫、網路呼叫和其他程式設計指令的情況。
執行緒是在 OS/2 上的基本執行單元,也是 OS/2 程序內部的可排程單元。執行緒的排程及優先順序是完全在核心中處理的。
Linux 核心使用的是程序模型,而不是執行緒模型。然而,Linux 核心為建立執行緒提供了一種輕量級的程序框架,而執行緒的真正實現是在使用者空間中。目前,可用的執行緒庫有很多種(LinuxThreads、NGPT、NPTL,等等)。本文的研究是以 LinuxThreads 庫為基礎進行的,但是其內容對 Rad Hat 的 Native POSIX Threading Library(本地 POSIX 執行緒庫,NPTL)也同樣適用。
本節介紹 OS/2 和 Linux 中的執行緒機制。內容涉及建立執行緒、設定執行緒屬性以及改變執行緒優先順序等所使用的呼叫。OS/2 與 Linux 中這些呼叫的對應關係如下表所示:
OS/2 | Linux | 類別 |
_beginthread |
pthread_create pthread_attr_init pthread_attr_setstacksize pthread_attr_destroy |
可對映的 |
_endthread |
pthread_exit |
可對映的 |
DosWaitThread |
pthread_join pthread_attr_setdetachstate pthread_detach |
可對映的 |
DosSetPriority |
程序 setpriority sched_setscheduler sched_setparam 執行緒 pthread_setschedparam pthread_setschedpolicy pthread_attr_setschedparam pthread_attr_setschedpolicy |
特定於上下文的 |
類別一列表示該 OS/2 指令是可對映的,還是特定於上下文的:
- 可對映的:這條 OS/2 指令可以對映為一條(或者若干條)指定的 Linux 指令,這需要對型別、引數、返回程式碼等進行檢查。
- 特定於上下文的:給定的 OS/2 指令在 Linux 中可能有等價的指令,也可能沒有,或者是 Linux 中能夠提供相似功能的指令不止一條。不論是哪種情況,我們都要根據應用程式的上下文來決定具體使用哪一條(或哪幾條)Linux 指令。
|
在 OS/2 中,我們用 _beginthread
這個系統呼叫來產生執行緒:
int _beginthread(void (*start_address) (void *), (void *) stack,
unsigned stack_size, void *arg);
Linux 則呼叫 pthread 庫中的 pthread_create()
來產生執行緒:
int pthread_create (pthread_t *thread_id, pthread_attr_t *threadAttr,
void * (*start_address)(void *), void * arg);
在 OS/2 系統呼叫 _beginthread
中,引數 start_address
表示新建立的執行緒將要執行的函式的地址。這個執行緒函式必須用 _Optlink
連結標記進行宣告和編譯。
在 Linux 庫呼叫 pthread_create()
中,引數 start_address
表示新建立的執行緒將要執行的函式的地址。
在 OS/2 中,系統呼叫 _beginthread()
的引數 arg 用於指定要傳遞給新建執行緒的引數。它指定了要傳遞給新建執行緒的資料項的地址。
在 Linux 中,庫呼叫 pthread_create()
的引數 arg 用於指定要傳遞給新建執行緒的引數。
OS/2 系統呼叫 call _beginthread()
的引數 stack_size 表示將要分配給新建執行緒的堆疊大小,單位為位元組。堆疊大小是 4K 的正整數倍,最小為 8K。
在 Linux 中,堆疊大小是在屬性物件中設定的;也就是說,我們將 pthread_attr_t
型別的 threadAttr
引數傳遞給 pthread_create()
庫呼叫。在設定這個物件的屬性之前,先要呼叫 pthread_attr_init()
對其進行初始化。通過呼叫 pthread_attr_destroy()
可以銷燬這個屬性物件:
int pthread_attr_init(pthread_attr_t *threadAttr);
int pthread_attr_destroy(pthread_attr_t *threadAttr);
請注意,所有形如 pthread_attr_setxxxx
的呼叫實現的功能都與 pthread_xxxx
這樣的呼叫(如果存在的話)類似,不過 pthread_attr_setxxxx
只能用於在建立執行緒之前對將要作為引數傳遞給 pthread_create
的屬性物件進行更新。同理,在建立好執行緒之後,我們可以使用任何形如 pthread_xxxx
的呼叫。
pthread_attr_setstacksize()
可以用於設定堆疊大小:
int pthread_attr_setstacksize(pthread_attr_t *threadAttr, int
stack_size);
在 OS/2 中並不存在顯式地維護與執行緒終止有關的執行緒狀態。不過,我們可以通過呼叫 DosWaitThread()
,讓一個執行緒顯式地等待程序內某個特定或非特定執行緒的終止。
在 Linux 中,預設情況下執行緒是以一種可連線(joinable)狀態被建立的。在可連線狀態下,其他執行緒可以在一個執行緒終止時對其進行同步,然後用 pthread_join()
函式恢復其終止程式碼。這個可連線執行緒的執行緒資源只有在它被插入之後才能釋放。
OS/2 用 DosWaitThread()
來等待一個執行緒的終止:
APIRET DosWaitThread(PTID ptid, ULONG option);
Linux 用 pthread_join
完成相同的工作 :
int pthread_join(pthread_t *thread, void **thread_return);
在分離(detached)狀態下,執行緒的資源線上程終止時會被立即釋放。您可以通過對執行緒屬性物件呼叫 pthread_attr_setdetachstate()
來設定分離狀態:
int pthread_attr_setdetachstate (pthread_attr_t *attr, int
detachstate);
以可連線狀態建立的執行緒以後還可以使用 pthread_detach()
呼叫來進入分離狀態:
int pthread_detach (pthread_t id);
在 OS/2 中,系統呼叫 _endthread()
用於終止執行緒。
Linux 中的等價庫呼叫為 pthread_exit()
。 retval
表示執行緒的返回值,其他執行緒可以通過呼叫 pthread_join()
獲取這個值:
int pthread_exit(void* retval);
OS/2 用系統呼叫 DosSetPriority()
改變程序,或正在執行的程序中的執行緒的優先順序:
int DosSetPriority(int scope, int class, int delta, int id);
在本例中,scope 是一個程序的 PRTYS_PROCESS
;一個執行緒級別的 PRTYS_THREAD
是該執行緒的優先順序。下面列出可以設定的不同優先順序:
- 不改變:
PRTYC_NOCHANGE
- 空閒時間:
PRTYC_IDLETIME
- 常規:
PRTYC_REGULAR
- 時間關鍵型:
PRTYC_TIMECRITICAL
- 固定高的優先順序:
PRTYC_FOREGROUNDSERVER
其中,引數 delta
是應用於該程序優先順序的改變數。其值必須在 -31 到 +31 之間。該值越高,優先順序就越高。當前程序或執行緒的 id 都為 0。
Linux 中提供了很多呼叫,可以用來修改或改變執行緒的優先順序。您應該根據應用程式的上下文環境選擇使用不同的呼叫。
Linux 系統呼叫 setpriority()
用來設定或修改普通程序和執行緒的優先順序。引數 scope 是 PRIO_PROCESS
。將 id 設為 0,可以修改當前程序(或執行緒)的優先順序。與前面一樣, delta
也是一個優先順序數值 —— 不過這一次 delta 的範圍變成了 -20 到 20。還要注意:在 Linux 中,delta 值越小,優先順序就越高。因此您可以對 IDLETIME
優先順序將 delta 設定為 +20,而對 REGULAR
優先順序則將 delta 設定為 0。
在 OS/2 中,優先順序的範圍是從 0 (優先順序最低)到 31 (優先順序最高)。但是在 Linux 中,普通的非實時程序優先順序範圍都是從 -20(優先順序最高)到 +20(優先順序最低)。在使用之前,必須對優先順序進行對映。
int setpriority(int scope, int id, int delta);
Linux 系統呼叫 sched_setscheduler
可以用來修改當前正在執行的程序的排程優先順序和排程策略:
int sched_setscheduler(pit_t pid, int policy, const struct sched_param *param);
引數 policy
是排程策略。policy 允許的值有 SCHED_OTHER
(用於普通的非實時排程)、 SCHED_RR
(實時的輪詢策略)和 SCHED_FIFO
(實時的 FIFO 策略)。
清單 1. 修改排程優先順序
struct sched_param { ... int sched_priority; ... };
此處, param
是指向一個代表排程優先順序的結構的指標。對於實時排程策略來說,該值的範圍為從 1 到 99。對於其他策略(普通的非實時程序)來說,該值是 0。
在 Linux 中,對於一種已知的排程策略來說,我們也可以使用系統呼叫 sched_setparam
來只修改程序的優先順序:
int sched_setparam(pit_t pid, const struct sched_param *param);
LinuxThreads
庫中的 pthread_setschedparam
呼叫是 sched_setscheduler
的一個用於執行緒的版本,可以動態地修改正在執行的執行緒排程優先順序和排程策略:
int pthread_setschedparam(pthread_t target_thread, int policy,
const struct sched_param *param);
引數 target_thread
代表要修改優先順序的執行緒,引數 param
表示優先順序。
LinuxThreads
庫中的 pthread_attr_setschedpolicy
呼叫和 pthread_attr_setschedparam
呼叫可以用於在建立執行緒之前設定執行緒屬性物件的排程策略和優先順序:
int pthread_attr_setschedpolicy(pthread attr_t *threadAttr, int policy);
int pthread_attr_setschedparam(pthread attr_t *threadAttr, const
struct sched_param *param);
下面這個例子可以非常清楚地說明建立執行緒和修改優先順序的實現從 OS/2 到 Linux 的對映方式。
在這個 OS/2 的例子中,thread1 是一個普通的執行緒,而 thread2 則是一個時間關鍵型實時執行緒。
清單 2. OS/2 執行緒程式碼
main () ...{
enum...{StackSize =120*1024}; /**//* stack size set to 120 K */
/**//* create a thread */
int thread1 = _beginThread (RegularThread, NULL, StackSize,
NULL);
int thread2 = _beginThread (CriticalThread, NULL,
StackSize, NULL);
}
/**//* Normal /Regular Priority Thread */
staticvoid RegularThread (void*) ...{
/**//* Set the priority of the thread. 0 is passed as an
argument to identify the current thread */
int iRc = DosSetPriority(PRTYS_THREAD, PRTYC_REGULAR, 20,
0);
_endThread();
}
/**//* Realtime time critical Priority Thread */
staticvoid CriticalThread (void*) ...{
int iRc = DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL,
20, 0);
_endThread();
}
下面是與上面這段 OS/2 程式碼等價的 Linux 程式碼:
清單 3. 等價的 Linux 執行緒程式碼
#define STATIC 0
staticvoid* RegularThread (void*);
staticvoid* CriticalThread (void*);
/**//* Regular non-realtime Thread function */
staticvoid* RegularThread (void*d)
...{
int priority =10; //0 for Regular, +20 for Idletime
/**//* Set the priority - normal non-realtime priority */
int irc = setpriority(PRIO_PROCESS, 0, priority);
pthread_exit(NULL);
}
/**//* Time Critical Realtime Thread function */
staticvoid* CriticalThread (void*d)
...{
if (STATIC ==0) ...{
/**//* change the thread priority dynamically */
struct sched_param param; // scheduling priority
int policy = SCHED_RR; // scheduling policy
/**//* Get the current thread id */
pthread_t thread_id = pthread_self();
/**//* To set the scheduling priority of the thread */
param.sched_priority =99;
int irc = pthread_setschedparam(thread_id, policy, ¶m);
}
pthread_exit(NULL);
}
int main (void)
...{
pthread_t thread1, thread2; // thread identifiers
pthread_attr_t threadAttr1, threadAttr2; // thread attributes
struct sched_param param; // scheduling priority
int policy = SCHED_RR; // scheduling policy - real time
int irc, rc;
rc = pthread_attr_init(&threadAttr1); /**//* init the attr 1*/
rc = pthread_attr_init(&threadAttr2); /**//* init the attr 2*/
/**//* Set the stack size of the thread */
irc = pthread_attr_setstacksize(&threadAttr1, 120*1024);
irc = pthread_attr_setstacksize(&threadAttr2, 120*1024);
/**//* Set thread to detached state. No need for pthread_join*/
irc = pthread_attr_setdetachstate(&threadAttr1,
PTHREAD_CREATE_DETACHED);
irc = pthread_attr_setdetachstate(&threadAttr2,
PTHREAD_CREATE_DETACHED);
if (STATIC ==1) ...{
相關推薦
將應用程式從 OS/2 移植到 Linux 上: 第 1 部分,執行緒、互斥鎖、訊號量
級別: 初級 2004 年 4 月 01 日 Linux 是新千年裡最傑出的作業系統,而傳統的作業系統,如 OS/2,現在正在逐漸淘汰出局。本系列文章是為那些正經受移植痛苦的開發人員撰寫的,可以幫助他們
WatchKit 框架: 將應用程式從褲兜裡取出來
你是否已經厭倦了總是需要將 iPhone 從褲兜裡取出來才能檢視訊息?你希望像 Michael knight 一樣,通過手腕就能與朋友通話嗎?蘋果已經讓其變得可能:全新的 Apple Watch 和非常酷的 WatchKit 框架。 在為 Apple Watch 開發應
從 0 開始學習 Linux 系列之「25.Posix 執行緒」
多執行緒概念 多執行緒技術是應用開發中非常重要的技術之一,幾乎大型的應用軟體都使用這個技術,這次一起來學習下 Linux 中的多執行緒開發基礎(其他的系統中概念也是類似的)。 在 Linux 中,一個簡單的程序可以看成只有一個單執行緒(主執行緒),因為只有一
C++程式設計思想 第2卷 第11章 併發 執行緒間協作 等待和訊號
在ZThread庫中 使用互斥鎖並允許任務掛起的基類是Condition 可以在條件Condition上呼叫wait()掛起一個任務 WaxOMatic.cpp有兩個程序 一個程序給Car上蠟 另一個程序給Car拋光 拋光程序在上臘程序完成前不能進行工作 並且上臘程序在汽
Linux基礎實訓(利用執行緒和互斥鎖)
實驗要求(linux) 1 定義一個長度為8的陣
【Linux】執行緒總結:執行緒同步 -互斥鎖,條件變數,訊號量實現多生產者多消費者模型
學習環境 : Centos6.5 Linux 核心 2.6 Linux執行緒部分總結分為兩部分:(1)執行緒的使用 ,(2)執行緒的同步與互斥。 第一部分執行緒的使用主要介紹,執行緒的概念,建立執行緒,執行緒退出,以及執行緒的終止與分離。【完
linux執行緒pthread互斥鎖
需要引用標頭檔案 <pthread.h> pthread_create(&thread1,NULL,(void *)&dealfunction,NULL); //建立執行
Linux下c++多執行緒和互斥鎖
一、多執行緒 多執行緒使用的是pthread庫,寫程式的時候需要引入標頭檔案pthread.h, g++編譯的時候需要加上該庫的依賴“-lpthread”。 1 先看程式便於理解,程式碼下面有對註釋的解釋。下面的程式碼含義是建立兩個執行緒,一個執行緒去計算某
Linux下多執行緒程式設計互斥鎖和條件變數的簡單使用
Linux下的多執行緒遵循POSIX執行緒介面,稱為pthread。編寫Linux下的多執行緒程式,需要使用標頭檔案pthread.h,連結時需要使用庫libpthread.a。執行緒是程序的一個實體,是CPU排程和分派的基本單位,它是比程序更小的能獨立執行的基本單位。執行緒
[譯] 使用 Kotlin 將你的應用程式從 iOS 轉換成 Android
原文地址:Converting your iOS App to Android Using Kotlin 原文作者:Lisa Luo 譯文出自:掘金翻譯計劃 本文永久連結:github.com/xitu/gold-m… 譯者:iWeslie 校對者:LoneyIsE
如何將應用程式exe註冊成服務,直接從後臺執行
方法一:使用windows自帶的命令sc 使用sc create 方法建立。 如:sc create CaptureScreen binpath= "F:\zwmei-project\decklink-learning\OutputBitmap\Deb
將 Win32 C/C++ 應用程式遷移到 POWER 上的 Linux,第 1 部分: 程序、執行緒和共享記憶體服務 (轉載)
特別是程序、執行緒和共享記憶體服務)到 POWER 上 Linux 的對映。本文可以幫助您確定哪種對映服務最適合您的需要。作者向您詳細介紹了他在移植 Win32 C/C++ 應用程式時遇到的 API 對映。概述有很多方式可以將 Win32 C/C++ 應用程式移植和遷移到 p
Zend Studio使用教程:將應用程式部署到Zend Server(1/2)
Zend Studio允許您從現有的SVN專案中建立一個新的PHP專案。在本教程中,您將獲的一個現有的SVN專案。 教程內容 在本教程中,您將學習: 從Zend Studio中的SVN建立一個新的PHP專案,您將獲得一個現有的SVN帳戶和專案。在本地Zend Ser
將應用程式加到Linux檔案系統後一起下載到ARM目標機上
將應用程式加到檔案系統中打包後一起下載方法總結如下: 假設ramdisk.gz存放在/home/cvtech/jx2410/root/下面,則操作如下: $cd /home/cvtech/jx2410/root/ $mk
linux如何將應用程式(使用原始碼安裝的軟體)全域性可用(以coverage為例)
前提:coverage是檢視python測試覆蓋率的一個工具,命令格式為coverage run *.py 方法有以下兩種: 1.加全域性變數 修改配置檔案/etc/profile。在裡面加上:注意這個路徑是安裝路徑,不是解壓縮包所在的地方。 export PATH
什麼時候應該將應用程式切分為多個容器?
圍繞著應該將應用程式的哪些部分切分為多個容器以及為什麼要這樣做,存在著很多困惑。我最近對Docker使用者郵箱列表的迴應促成了今天的文章。在這篇文章中我打算評估一個映象化的Java應用程式,它歷史上曾經執行在一個單一的Tomcat伺服器裡,並解釋為什麼我會把它切分為獨立的容器。為了讓事情有趣
將應用程式新增到gnome3的全域性選單中(並支援修改為預設程式)
在gnome3中,如果將滑鼠移動到左上角,就會出現一個程式選單,類似於win8中的start介面,在這裡直接鍵入英文就可以快速索引程式,十分方便。不過像deadbeef(筆者喜歡的一個輕量級音樂播放器)這種從網上獲取的可執行檔案無法作為程式出現在gnome3的程式選單中,而
【鐵匠Smith先生的專欄】關注Linux系統軟體開發、多媒體圖形技術、Linux OS技術、多程序多執行緒併發網路程式設計、架構模式研究與實踐、AI等新技術動向、C/C++最新程式設計技術、開原始碼整合與應用等
關注Linux系統軟體開發、多媒體圖形技術、Linux OS技術、多程序多執行緒併發網路程式設計、架構模式研究與實踐、AI等新技術動向、C/C++最新程式設計技術、開原始碼整合與應用等...
MFC中如何將應用程式的配置資訊儲存到登錄檔中(二)
在上一篇中介紹了幾個寫入登錄檔資料和讀取登錄檔資料的介面,並介紹了使用方法。 這一片教你如何使得你的應用程式在下次開啟時保持上一次關閉前的狀態。 在上一篇新增的程式碼的基礎上,要新增WM_CLOSE訊息的響應函式,因為我們只有在視窗關閉前要儲存視窗的位置資訊,所以儲存視窗位
將Wordpress站點從虛擬主機移植到本地伺服器
為了方便對模板就行修改,經常需要映象wordpress站點到本地。 本文將一步一步的介紹操作過程以及需要注意的事項 1. 環境說明 本地伺服器使用WAMP 假定線上站點域名為 www.domain_name.com 本地站點連結為 localhost:8080/doma