1. 程式人生 > >將應用程式從 OS/2 移植到 Linux 上: 第 1 部分,執行緒、互斥鎖、訊號量

將應用程式從 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 指令。
Linux 入門

自從 1991 年 Linux 誕生以來,就隨著它的流行而不斷成長起來。Linux 的主要優勢在於它是開放原始碼的自由軟體(有關自由軟體的詳細內容,請您參看本說明框底部的資源清單)

當 Linux 最新的主力版本(核心 2.6)釋出時,越來越多的公司正將它們的業務過程轉移到開放標準上來,並且釋出了一些基於 Linux 的產品。

在大公司中,IBM 在開放原始碼社團中的表現是最為活躍的。IBM 尤其關注一些特定的領域,比如如何改進 Linux 的可升級能力和穩定性,重點在企業計算方面。現在,大多數 IBM eServer 伺服器都捆綁了 Linux。

作為其 Linux 計劃的一部分,IBM 正積極參與到若干專案中,致力於將基於 OS/2 等遺留作業系統的產品遷移到 Linux 上。

  • 自由軟體基金會能告訴您有關 自由軟體 的全部情況。
  • 要更好地理解自由軟體和開放原始碼軟體之間的區別,請您閱讀 開放原始碼規範
  • IBM developerWorks 上有一個頁面專門為 Linux 初學者提供資料和資訊。
  • 目前,大多數 IBM eServer伺服器都捆綁了 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,
   
200);
               _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, &param);
       }

       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++程式設計思想 211章 併發 執行間協作 等待和訊號

在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