青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

C++樂園

C/C++ 交流

  C++博客 :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
  12 隨筆 :: 18 文章 :: 14 評論 :: 0 Trackbacks

將 Win32 C/C++ 應(yīng)用程序遷移到 POWER 上的 Linux,第 1 部分: 進程、線程和共享內(nèi)存服務(wù)

developerWorks
文檔選項
將打印機的版面設(shè)置成橫向打印模式

打印本頁

將此頁作為電子郵件發(fā)送

將此頁作為電子郵件發(fā)送


級別: 初級

Nam Keung (namkeung@us.ibm.com), 高級程序員
Chakarat Skawratananond (chakarat@us.ibm.com), pSeries Linux 技術(shù)顧問

2005 年 1 月 06 日

本文的內(nèi)容是 Win32 API(特別是進程、線程和共享內(nèi)存服務(wù))到 POWER 上 Linux 的映射。本文可以幫助您確定哪種映射服務(wù)最適合您的需要。作者向您詳細(xì)介紹了他在移植 Win32 C/C++ 應(yīng)用程序時遇到的 API 映射。

概述

有很多方式可以將 Win32 C/C++ 應(yīng)用程序移植和遷移到 pSeries 平臺。您可以使用免費軟件或者第三方工具來將 Win32 應(yīng)用程序代碼移到 Linux。在我們的方案中,我們決定使用一個可移植層來抽象系統(tǒng) API 調(diào)用。可移植層將使我們的應(yīng)用程序具有以下優(yōu)勢:

  • 與硬件無關(guān)。
    • 與操作系統(tǒng)無關(guān)。
    • 與操作系統(tǒng)上版本與版本間的變化無關(guān)。
  • 與操作系統(tǒng) API 風(fēng)格及錯誤代碼無關(guān)。
  • 能夠統(tǒng)一地在對 OS 的調(diào)用中置入性能和 RAS 鉤子(hook)。

 

由于 Windows 環(huán)境與 pSeries Linux 環(huán)境有很大區(qū)別,所以進行跨 UNIX 平臺的移植比進行從 Win32 平臺到 UNIX 平臺的移植要容易得多。這是可以想到的,因為很多 UNIX 系統(tǒng)都使用共同的設(shè)計理念,在應(yīng)用程序?qū)佑蟹浅6嗟念愃浦帯2贿^,Win32 API 在移植到 Linux 時是受限的。本文剖析了由于 Linux 和 Win32 之間設(shè)計的不同而引發(fā)的問題。





回頁首


初始化和終止

在 Win2K/NT 上,DLL 的初始化和終止入口點是 _DLL_InitTerm 函數(shù)。當(dāng)每個新的進程獲得對 DLL 的訪問時,這個函數(shù)初始化 DLL 所必需的環(huán)境。當(dāng)每個新的進程釋放其對 DLL 的訪問時,這個函數(shù)為那個環(huán)境終止 DLL。當(dāng)您鏈接到那個 DLL 時,這個函數(shù)會自動地被調(diào)用。對應(yīng)用程序而言,_DLL_InitTerm 函數(shù)中包含了另外一個初始化和終止例程。

在 Linux 上,GCC 有一個擴展,允許指定當(dāng)可執(zhí)行文件或者包含它的共享對象啟動或停止時應(yīng)該調(diào)用某個函數(shù)。語法是 __attribute__((constructor))__attribute__((destructor))。這些基本上與構(gòu)造函數(shù)及析構(gòu)函數(shù)相同,可以替代 glibc 庫中的 _init 和 _fini 函數(shù)。

這些函數(shù)的 C 原型是:
void __attribute__ ((constructor)) app_init(void);
                        void __attribute__ ((destructor)) app_fini(void);

				Win32 sample
                        _DLL_InitTerm(HMODULE modhandle, DWORD fdwReason, LPVOID lpvReserved)
                        {
                        WSADATA			Data;
                        switch (fdwReason)
                        {
                        case DLL_PROCESS_ATTACH:
                        if (_CRT_init() == -1)
                        return 0L;
                        /* start with initialization code */
                        app_init();
                        break;
                        case DLL_PROCESS_DETACH:
                        /* Start with termination code*/
                        app_fini();
                        _CRT_term();
                        break;
                        …..
                        default:
                        /* unexpected flag value - return error indication */
                        return 0UL;
                        }	return 1UL;		/* success */
                        }
                        





回頁首


進程服務(wù)

Win32 進程模型沒有與 fork()exec() 直接相當(dāng)?shù)暮瘮?shù)。在 Linux 中使用 fork() 調(diào)用總是會繼承所有內(nèi)容,與此不同, CreateProcess() 接收用于控制進程創(chuàng)建方面的顯式參數(shù),比如文件句柄繼承。

CreateProcess API 創(chuàng)建一個包含有一個或多個在此進程的上下文中運行的線程的新進程,子進程與父進程之間沒有關(guān)系。在 Windows NT/2000/XP 上,返回的進程 ID 是 Win32 進程 ID。在 Windows ME 上,返回的進程 ID 是除去了高位(high-order bit)的 Win32 進程 ID。當(dāng)創(chuàng)建的進程終止時,所有與此進程相關(guān)的數(shù)據(jù)都從內(nèi)存中刪除。

為了在 Linux 中創(chuàng)建一個新的進程, fork() 系統(tǒng)調(diào)用會復(fù)制那個進程。新進程創(chuàng)建后,父進程和子進程的關(guān)系就會自動建立,子進程默認(rèn)繼承父進程的所有屬性。Linux 使用一個不帶任何參數(shù)的調(diào)用創(chuàng)建新的進程。 fork() 將子進程的進程 ID 返回給父進程,而不返回給子進程任何內(nèi)容。

Win32 進程同時使用句柄和進程 ID 來標(biāo)識,而 Linux 沒有進程句柄。

進程映射表

Win32 Linux
CreateProcess fork()
execv()
TerminateProcess kill
ExitProcess() exit()
GetCommandLine argv[]
GetCurrentProcessId getpid
KillTimer alarm(0)
SetEnvironmentVariable putenv
GetEnvironmentVariable getenv
GetExitCodeProcess waitpid

創(chuàng)建進程服務(wù)

在 Win32 中, CreateProcess() 的第一個參數(shù)指定要運行的程序,第二個參數(shù)給出命令行參數(shù)。CreateProcess 將其他進程參數(shù)作為參數(shù)。倒數(shù)第二個參數(shù)是一個指向某個 STARTUPINFORMATION 結(jié)構(gòu)體的指針,它為進程指定了標(biāo)準(zhǔn)的設(shè)備以及其他關(guān)于進程環(huán)境的啟動信息。在將 STARTUPINFORMATION 結(jié)構(gòu)體的地址傳給 CreateProcess 以重定向進程的標(biāo)準(zhǔn)輸入、標(biāo)準(zhǔn)輸出和標(biāo)準(zhǔn)錯誤之前,您需要設(shè)置這個結(jié)構(gòu)體的 hStdin、hStdout 和 hStderr 成員。最后一個參數(shù)是一個指向某個 PROCESSINFORMATION 結(jié)構(gòu)體的指針,由被創(chuàng)建的進程為其添加內(nèi)容。進程一旦啟動,它將包含創(chuàng)建它的進程的句柄以及其他內(nèi)容。

				Win32 example
                        PROCESS_INFORMATION    procInfo;
                        STARTUPINFO	        startupInfo;
                        typedef DWORD          processId;
                        char                   *exec_path_name
                        char                   *_cmd_line;
                        GetStartupInfo( &startupInfo );     // You must fill in this structure
                        if( CreateProcess( exec_path_name,  // specify the executable program
                        _cmd_line,   // the command line arguments
                        NULL,       // ignored in Linux
                        NULL,       // ignored in Linux
                        TRUE,       // ignored in Linux
                        DETACHED_PROCESS | HIGH_PRIORITY_CLASS,
                        NULL,       // ignored in Linux
                        NULL,       // ignored in Linux
                        &startupInfo,
                        &procInfo))
                        *processId = procInfo.dwProcessId;
                        else
                        {
                        *processId = 0;
                        return RC_PROCESS_NOT_CREATED;
                        }
                        

在 Linux 中,進程 ID 是一個整數(shù)。Linux 中的搜索目錄由 PATH 環(huán)境變量(exec_path_name)決定。 fork() 函數(shù)建立父進程的一個副本,包括父進程的數(shù)據(jù)空間、堆和棧。 execv() 子例程使用 exec_path_name 將調(diào)用進程當(dāng)前環(huán)境傳遞給新的進程。

這個函數(shù)用一個由 exec_path_name 指定的新的進程映像替換當(dāng)前的進程映像。新的映像構(gòu)造自一個由 exec_path_name 指定的正規(guī)的、可執(zhí)行的文件。由于調(diào)用的進程映像被新的進程映像所替換,所以沒有任何返回。

				Equivalent Linux code
                        #include <stdlib.h>
                        #include <stdio.h>
                        int    processId;
                        char  *exec_path_name;
                        char  *	cmd_line ;
                        cmd_line = (char *) malloc(strlen(_cmd_line ) + 1 );
                        if(cmd_line == NULL)
                        return RC_NOT_ENOUGH_MEMORY;
                        strcpy(cmd_line, _cmd_line);
                        if( ( *processId =
                        fork() ) == 0 )		// Create child
                        {
                        char		*pArg, *pPtr;
                        char		*argv[WR_MAX_ARG + 1];
                        int		 argc;
                        if( ( pArg = strrchr( exec_path_name, '/' ) ) != NULL )
                        pArg++;
                        else
                        pArg = exec_path_name;
                        argv[0] = pArg;
                        argc = 1;
                        if( cmd_line != NULL && *cmd_line != '\0' )
                        {
                        pArg = strtok_r(cmd_line, " ", &pPtr);
                        while( pArg != NULL )
                        {
                        argv[argc] = pArg;
                        argc++;
                        if( argc >= WR_MAX_ARG )
                        break;
                        pArg = strtok_r(NULL, " ", &pPtr);
                        }
                        }
                        argv[argc] = NULL;
                        execv(exec_path_name, argv);
                        free(cmd_line);
                        exit( -1 );
                        }
                        else if( *processId == -1 )
                        {
                        *processId = 0;
                        free(cmd_line);
                        return RC_PROCESS_NOT_CREATED;
                        }
                        

終止進程服務(wù)

在 Win32 進程中,父進程和子進程可能需要單獨訪問子進程所繼承的由某個句柄標(biāo)識的對象。父進程可以創(chuàng)建一個可訪問而且可繼承的副本句柄。Win32 示例代碼使用下面的方法終止進程:

  • 使用 OpenProcess 來獲得指定進程的句柄。
  • 使用 GetCurrentProcess 獲得其自己的句柄。
  • 使用 DuplicateHandle 來獲得一個來自同一對象的句柄作為原始句柄。

 

如果函數(shù)成功,則使用 TerminateThread 函數(shù)來釋放同一進程上的主線程。然后使用 TerminateThread 函數(shù)來無條件地使一個進程退出。它啟動終止并立即返回。

				Win32 sample code
                        if( thread != (HANDLE) NULL )
                        {
                        HANDLE	thread_dup;
                        if( DuplicateHandle( OpenProcess(PROCESS_ALL_ACCESS, TRUE,  processId),
                        thread,
                        GetCurrentProcess(),
                        &thread_dup,  //Output
                        0,
                        FALSE,
                        DUPLICATE_SAME_ACCESS ))
                        {
                        TerminateThread( thread_dup, 0);
                        }
                        }
                        TerminateProcess(
                        OpenProcess(PROCESS_ALL_ACCESS, TRUE,
                        processId),
                        (UINT)0 );
                        

在 Linux 中,使用 kill 子例程發(fā)送 SIGTERM 信號來終止特定進程(processId)。然后調(diào)用設(shè)置 WNOHANG 位的 waitpid 子例程。這將檢查特定的進程并終止。

				Equivalent  Linux code
                        pid_t	nRet;
                        int	status;
                        kill( processId, SIGTERM );
                        nRet = waitpid( processId, &status, WNOHANG);  //Check specified
                        process is terminated
                        

進程依然存在服務(wù)

Win32 OpenProcess 返回特定進程(processId)的句柄。如果函數(shù)成功,則 GetExitCodeProcess 將獲得特定進程的狀態(tài),并檢查進程的狀態(tài)是否是 STILL_ACTIVE。

				Win 32 sample
                        HANDLE      nProc;
                        DWORD       dwExitCode;
                        nProc = OpenProcess(PROCESS_ALL_ACCESS, TRUE, processId);
                        if ( nProc != NULL)
                        {
                        GetExitCodeProcess( nProc, &dwExitCode );
                        if (dwExitCode == STILL_ACTIVE )
                        return RC_PROCESS_EXIST;
                        else
                        return RC_PROCESS_NOT_EXIST;
                        }
                        else
                        return RC_PROCESS_NOT_EXIST;
                        

在 Linux 中,使用 kill 子例程發(fā)送通過 Signal 參數(shù)指定的信號給由 Process 參數(shù)(processId)指定的特定進程。Signal 參數(shù)是一個 null 值,會執(zhí)行錯誤檢查,但不發(fā)送信號。

				Equivalent Linux code
                        if ( kill ( processId, 0 ) == -1 && errno == ESRCH ) // No process can
                        be found
                        // corresponding to processId
                        return RC_PROCESS_NOT_EXIST;
                        else
                        return RC_PROCESS_EXIST;
                        





回頁首


線程模型

線程 是系統(tǒng)分配 CPU 時間的基本單位;當(dāng)?shù)却{(diào)度時,每個線程保持信息來保存它的“上下文”。每個線程都可以執(zhí)行程序代碼的任何部分,并共享進程的全局變量。

構(gòu)建于 clone() 系統(tǒng)調(diào)用之上的 LinuxThreads 是一個 pthreads 兼容線程系統(tǒng)。因為線程由內(nèi)核來調(diào)度,所以 LinuxThreads 支持阻塞的 I/O 操作和多處理器。不過,每個線程實際上是一個 Linux 進程,所以一個程序可以擁有的線程數(shù)目受內(nèi)核所允許的進程總數(shù)的限制。Linux 內(nèi)核沒有為線程同步提供系統(tǒng)調(diào)用。Linux Threads 庫提供了另外的代碼來支持對互斥和條件變量的操作(使用管道來阻塞線程)。

對有外加 LinuxThreads 的信號處理來說,每個線程都會繼承信號處理器(如果派生這個線程的父進程注冊了一個信號處理器的話。只有在 Linux Kernel 2.6 和更高版本中支持的新特性才會包含 POSIX 線程支持,比如 用于 Linux 的 Native POSIX Thread Library(NPTL)。

線程同步、等待函數(shù)、線程本地存儲以及初始化和終止抽象是線程模型的重要部分。在這些之下,線程服務(wù)只負(fù)責(zé):

  • 新線程被創(chuàng)建,threadId 被返回。
  • 通過調(diào)用 pthread_exit 函數(shù)可以終止當(dāng)前的新線程。

 

線程映射表

Win32 Linux
_beginthread pthread_attr_init
pthread_attr_setstacksize
pthread_create
_endthread pthread_exit
TerminateThread pthread_cancel
GetCurrentThreadId pthread_self

線程創(chuàng)建

Win32 應(yīng)用程序使用 C 運行期庫,而不使用 Create_Thread API。使用了 _beginthread 和 _endthread 例程。這些例程會考慮任何可重入性(reentrancy)和內(nèi)存不足問題、線程本地存儲、初始化和終止抽象。

Linux 使用 pthread 庫調(diào)用 pthread_create() 來派生一個線程。

threadId 作為一個輸出參數(shù)返回。為創(chuàng)建一個新線程,要傳遞一組參數(shù)。當(dāng)新線程被創(chuàng)建時,這些參數(shù)會執(zhí)行一個函數(shù)。stacksize 用作新線程的棧的大小(以字節(jié)為單位),當(dāng)新線程開始執(zhí)行時,實際的參數(shù)被傳遞給函數(shù)。

指定線程程序(函數(shù))

進行創(chuàng)建的線程必須指定要執(zhí)行的新線程的啟動函數(shù)的代碼。啟動地址是 threadproc 函數(shù)(帶有一個單獨的參數(shù),即 threadparam)的名稱。如果調(diào)用成功地創(chuàng)建了一個新線程,則返回 threadId。Win32 threadId 的類型定義是 HANDLE。Linux threadId 的類型定義是 pthread_t。

threadproc
要執(zhí)行的線程程序(函數(shù))。它接收一個單獨的 void 參數(shù)。
threadparam
線程開始執(zhí)行時傳遞給它的參數(shù)。

設(shè)置棧大小

在 Win32 中,線程的棧由進程的內(nèi)存空間自動分配。系統(tǒng)根據(jù)需要增加棧的大小,并在線程終止時釋放它。在 Linux 中,棧的大小在 pthread 屬性對象中設(shè)置;pthread_attr_t 傳遞給庫調(diào)用 pthread_create()

				Win32 sample
                        int		hThrd;
                        DWORD          dwIDThread;
                        unsigned       stacksize;
                        void           *thrdparam; //parameter to be passed to the thread when it
                        //begins execution
                        HANDLE         *threadId;
                        if( stacksize < 8192 )
                        stacksize = 8192;
                        else
                        stacksize = (stacksize/4096+1)*4096;
                        hThrd = _beginthread( thrdproc,    // Definition of a thread entry
                        //point
                        NULL,
                        stacksize,
                        thrdparam);
                        if (hThrd == -1)
                        return RC_THREAD_NOT_CREATED);
                        *threadId = (HANDLE) hThrd;
                        __________________________________________________________________
                        Equivalent Linux code
                        #include <pthread.h>
                        pthread_t   *threadId;
                        void         thrdproc  (void *data);  //the thread procedure (function) to
                        //be executed.
                        //It receives a single void parameter
                        void        *thrdparam; //parameter to be passed to the thread when it
                        //begins execution
                        pthread_attr_t  attr;
                        int             rc = 0;
                        if (thrdproc == NULL || threadId == NULL)
                        return RC_INVALID_PARAM);
                        if (rc = pthread_attr_init(&attr))
                        return RC_THREAD_NOT_CREATED);  // EINVAL, ENOMEM
                        if (rc = pthread_attr_setstacksize(&attr, stacksize))
                        return RC_THREAD_NOT_CREATED);   // EINVAL, ENOSYS
                        if (rc = pthread_create(threadId, &attr, (void*(*)(void*))thrdproc,
                        thrdparam))
                        return RC_THREAD_NOT_CREATED);      // EINVAL, EAGAIN
                        

終止線程服務(wù)

在 Win32 中,一個線程可以使用 TerminateThread 函數(shù)終止另一個線程。不過,線程的棧和其他資源將不會被收回。如果線程終止自己,則這樣是可取的。在 Linux 中,pthread_cancel 可以終止由具體的 threadId 所標(biāo)識的線程的執(zhí)行。

Win32 Linux
TerminateThread((HANDLE *) threadId, 0); pthread_cancel(threadId);

線程狀態(tài)

在 Linux 中,線程默認(rèn)創(chuàng)建為可合并(joinable)狀態(tài)。另一個線程可以使用 pthread_join() 同步線程的終止并重新獲得終止代碼。可合并線程的線程資源只有在其被合并后才被釋放。

Win32 使用 WaitForSingleObject() 來等待線程終止。

Linux 使用 pthread_join 完成同樣的事情。

Win32 Linux
unsigned long rc;

rc = (unsigned long) WaitForSingleObject (threadId, INIFITE);
unsigned long rc=0;

rc = pthread_join(threadId,
void **status);

結(jié)束當(dāng)前線程服務(wù)的執(zhí)行

在 Win32 中,使用 _endthread() 來結(jié)束當(dāng)前線程的執(zhí)行。在 Linux 中,推薦使用 pthread_exit() 來退出一個線程,以避免顯式地調(diào)用 exit 例程。在 Linux 中,線程的返回值是 retval,可以由另一個線程調(diào)用 pthread_join() 來獲得它。

Win32 Linux
_endthread(); pthread_exit(0);

獲得當(dāng)前線程 ID 服務(wù)

在 Win32 進程中,GetCurrentThreadId 函數(shù)獲得進行調(diào)用的線程的線程標(biāo)識符。Linux 使用 pthread_self() 函數(shù)來返回進行調(diào)用的線程的 ID。

Win32 Linux
GetCurrentThreadId() pthread_self()

sleep 服務(wù)

用于 Win32 Sleep 函數(shù)的時間段的單位是毫秒,可以是 INFINITE,在這種情況下線程將永遠(yuǎn)不會再重新開始。 Linux sleep 函數(shù)類似于 Sleep,但是時間段以秒來計。要獲得毫秒級的精度,則使用 nanosleep 函數(shù)來提供同樣的服務(wù)。

Win32 Equivalent Linux code
Sleep (50) struct timespec timeOut,remains;

timeOut.tv_sec = 0;
timeOut.tv_nsec = 500000000; /* 50 milliseconds */

nanosleep(&timeOut, &remains);

Win32 SleepEx 函數(shù)掛起 當(dāng)前線程,直到下面事件之一發(fā)生:

  • 一個 I/O 完成回調(diào)函數(shù)被調(diào)用。
  • 一個異步過程調(diào)用(asynchronous procedure call,APC)排隊到此線程。
  • 最小超時時間間隔已經(jīng)過去。

 

Linux 使用 sched_yield 完成同樣的事情。

Win32 Linux
SleepEx (0,0) sched_yield()





回頁首


共享內(nèi)存服務(wù)

共享內(nèi)存允許多個進程將它們的部分虛地址映射到一個公用的內(nèi)存區(qū)域。任何進程都可以向共享內(nèi)存區(qū)域?qū)懭霐?shù)據(jù),并且數(shù)據(jù)可以由其他進程讀取或修改。共享內(nèi)存用于實現(xiàn)進程間通信媒介。不過,共享內(nèi)存不為使用它的進程提供任何訪問控制。使用共享內(nèi)存時通常會同時使用“鎖”。

一個典型的使用情形是:

  1. 某個服務(wù)器創(chuàng)建了一個共享內(nèi)存區(qū)域,并建立了一個共享的鎖對象。
  2. 某個客戶機連接到服務(wù)器所創(chuàng)建的共享內(nèi)存區(qū)域。
  3. 客戶機和服務(wù)器雙方都可以使用共享的鎖對象來獲得對共享內(nèi)存區(qū)域的訪問。
  4. 客戶機和服務(wù)器可以查詢共享內(nèi)存區(qū)域的位置。

 

共享內(nèi)存映射表

Win32 Linux
CreateFileMaping,
OpenFileMapping
mmap
shmget
UnmapViewOfFile munmap
shmdt
MapViewOfFile mmap
shmat

創(chuàng)建共享內(nèi)存資源

Win32 通過共享的內(nèi)存映射文件來創(chuàng)建共享內(nèi)存資源。Linux 使用 shmget/mmap 函數(shù)通過直接將文件數(shù)據(jù)合并入內(nèi)存來訪問文件。內(nèi)存區(qū)域是已知的作為共享內(nèi)存的段。

文件和數(shù)據(jù)也可以在多個進程和線程之間共享。不過,這需要進程或線程之間同步,由應(yīng)用程序來處理。

如果資源已經(jīng)存在,則 CreateFileMapping() 重新初始化共享資源對于進程的約定。如果沒有足夠的空閑內(nèi)存來處理錯誤的共享資源,此調(diào)用可能會失敗。 OpenFileMapping() 需要共享資源必須已經(jīng)存在;這個調(diào)用只是請求對它的訪問。

在 Win32 中,CreateFileMapping 不允許您增加文件大小,但是在 Linux 中不是這樣。在 Linux 中,如果資源已經(jīng)存在,它將被重新初始化。它可能被銷毀并重新創(chuàng)建。Linux 創(chuàng)建可以通過名稱訪問的共享內(nèi)存。 open() 系統(tǒng)調(diào)用確定映射是否可讀或可寫。傳遞給 mmap() 的參數(shù)必須不能與 open() 時請求的訪問相沖突。 mmap() 需要為映射提供文件的大小(字節(jié)數(shù))。

對 32-位內(nèi)核而言,有 4GB 虛地址空間。最前的 1 GB 用于設(shè)備驅(qū)動程序。最后 1 GB 用于內(nèi)核數(shù)據(jù)結(jié)構(gòu)。中間的 2GB 可以用于共享內(nèi)存。當(dāng)前,POWER 上的 Linux 允許內(nèi)核使用 4GB 虛地址空間,允許用戶應(yīng)用程序使用最多 4GB 虛地址空間。

映射內(nèi)存訪問保護位

Win32 Linux
PAGE_READONLY PROT_READ
PAGE_READWRITE (PROT_READ | PROT_WRITE)
PAGE_NOACCESS PROT_NONE
PAGE_EXECUTE PROT_EXEC
PAGE_EXECUTE_READ (PROT_EXEC |PROT_READ)
PAGE_EXECUTE_READWRITE (PROT_EXEC | PROT_READ | PROT_WRITE)

要獲得 Linux 共享內(nèi)存的分配,您可以查看 /proc/sys/kernel 目錄下的 shmmax、shmmin 和 shmall。

在 Linux 上增加共享內(nèi)存的一個示例:
echo 524288000 > /proc/sys/kernel/shmmax

最大共享內(nèi)存增加到 500 MB。

下面是創(chuàng)建共享內(nèi)存資源的 Win32 示例代碼,以及相對應(yīng)的 Linux nmap 實現(xiàn)。

				Win32 sample code
                        typedef struct
                        {
                        // This receives a pointer within the current process at which the
                        // shared memory is located.
                        // The same shared memory may reside at different addresses in other
                        // processes which share it.
                        void *	location;
                        HANDLE	hFileMapping;
                        }mem_shared_struct, *mem_shared, *token;
                        mem_shared_struct   *token;
                        if ((*token = (mem_shared) malloc(sizeof(mem_shared_struct))) == NULL)
                        return RC_NOT_ENOUGH_MEMORY;
                        if (newmode == new_shared_create)
                        (*token)->hFileMapping = CreateFileMapping((HANDLE) 0xFFFFFFFF, NULL,
                        PAGE_READWRITE,
                        0,
                        (DWORD) size,
                        (LPSTR) name);
                        else
                        (*token)->hFileMapping = OpenFileMapping(FILE_MAP_ALL_ACCESS,
                        FALSE,
                        (LPSTR) name);
                        if ((*token)->hFileMapping == NULL)
                        {
                        free( *token );
                        return RC_SHM_NOT_CREATED );
                        }
                        (*token)->location = MapViewOfFile((*token)->hFileMapping,
                        FILE_MAP_READ | FILE_MAP_WRITE,
                        0, 0, 0);
                        if ((*token)->location == NULL)
                        {
                        CloseHandle((*token)->hFileMapping);
                        free(*token);
                        return RC_OBJECT_NOT_CREATED;
                        }
                        ____________________________________________________________________
                        Equivalent Linux code
                        typedef struct
                        {
                        void    *location;
                        int	 nFileDes;
                        cs_size	 nSize;
                        char	 *pFileName;
                        }mem_shared_struct, *mem_shared, token;
                        mode_t	mode=0;
                        int	flag=0;
                        int	i, ch='\0';
                        char   name_buff[128];
                        if (newmode == new_shared_create)
                        flag = O_CREAT;
                        else if (newmode != new_shared_attach)
                        return RC_INVALID_PARAM;
                        if ((*token = (mem_shared) malloc(sizeof(mem_shared_struct))) == NULL)
                        return RC_NOT_ENOUGH_MEMORY;
                        strcpy(name_buff, "/tmp/" );
                        strcat(name_buff, name );
                        if(((*token)->pFileName = malloc(strlen(name_buff)+1)) == NULL )
                        {
                        free(*token);
                        return RC_NOT_ENOUGH_MEMORY;
                        }
                        mode |= S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
                        flag |= O_RDWR;
                        if(newmode == new_shared_create)
                        remove(name_buff);
                        if(((*token)->nFileDes = open(name_buff, flag, mode)) < 0)
                        {
                        free((*token)->pFileName);
                        free(*token);
                        return RC_OBJECT_NOT_CREATED;
                        }
                        if(newmode == new_shared_create)
                        {
                        lseek((*token)->nFileDes, size - 1, SEEK_SET);
                        write((*token)->nFileDes, &ch, 1);
                        }
                        if(lseek((*token)->nFileDes, 0, SEEK_END) < size)
                        {
                        free((*token)->pFileName);
                        free(*token);
                        return RC_MEMSIZE_ERROR;
                        }
                        (*token)->location = mmap( 0, size,
                        PROT_READ | PROT_WRITE,
                        MAP_VARIABLE | MAP_SHARED,
                        (*token)->nFileDes,
                        0);
                        if((int)((*token)->location) == -1)
                        {
                        free((*token)->pFileName);
                        free(*token);
                        return RC_OBJECT_NOT_CREATED;
                        }
                        (*token)->nSize = size;strcpy((*token)->pFileName, name_buff);
                        

刪除共享內(nèi)存資源

為銷毀共享內(nèi)存資源,munmap 子例程要取消被映射文件區(qū)域的映射。munmap 子例程只是取消對 mmap 子例程的調(diào)用而創(chuàng)建的區(qū)域的映射。如果某個區(qū)域內(nèi)的一個地址被 mmap 子例程取消映射,并且那個區(qū)域后來未被再次映射,那么任何對那個地址的引用將導(dǎo)致給進程發(fā)出一個 SIGSEGV 信號。

Win32 等價的 Linux 代碼
UnmapViewOfFile(token->location);

CloseHandle(token->hFileMapping);
munmap(token->location, token->nSize);

close(token->nFileDes);

remove(token->pFileName);

free(token->pFileName);




回頁首


結(jié)束語

本文介紹了關(guān)于初始化和終止、進程、線程及共享內(nèi)存服務(wù)從 Win32 API 到 POWER 上 Linux 的映射。這絕對沒有涵蓋所有的 API 映射,而且讀者只能將此信息用作將 Win32 C/C++ 應(yīng)用程序遷移到 POWER Linux 的一個參考。

特別聲明

IBM、eServer 和 pSeries 是 IBM Corporation 在美國和/或其它國家或地區(qū)的商標(biāo)。

UNIX 是 The Open Group 在美國和其它國家或地區(qū)的注冊商標(biāo)。

Microsoft 和 Windows 是 Microsoft Corporation 在美國和/或其它國家或地區(qū)的商標(biāo)或注冊商標(biāo)。

所有其他商標(biāo)和注冊商標(biāo)是它們相應(yīng)公司的財產(chǎn)。

此出版物/說明是在美國完成的。IBM 可能不在其他國家或地區(qū)提供在此討論的產(chǎn)品、程序、服務(wù)或特性,而且信息可能會不加聲明地加以修改。有關(guān)您當(dāng)前所在區(qū)域的產(chǎn)品、程序、服務(wù)和特性的信息,請向您當(dāng)?shù)氐?IBM 代表咨詢。任何對 IBM 產(chǎn)品、程序、服務(wù)或者特性的引用并非意在明示或暗示只能使用 IBM 的產(chǎn)品、程序、服務(wù)或者特性。只要不侵犯 IBM 的知識產(chǎn)權(quán),任何同等功能的產(chǎn)品、程序、服務(wù)或特性,都可以代替 IBM 產(chǎn)品、程序、服務(wù)或特性。

涉及非 IBM 產(chǎn)品的信息可從這些產(chǎn)品的供應(yīng)商、其出版說明或其他可公開獲得的資料中獲取,并不構(gòu)成 IBM 對此產(chǎn)品的認(rèn)可。非 IBM 價目及性能數(shù)字資源取自可公開獲得的信息,包括供應(yīng)商的聲明和供應(yīng)商的全球主頁。 IBM 沒有對這些產(chǎn)品進行測試,也無法確認(rèn)其性能的精確性、兼容性或任何其他關(guān)于非 IBM 產(chǎn)品的聲明。有關(guān)非 IBM 產(chǎn)品性能的問題應(yīng)當(dāng)向這些產(chǎn)品的供應(yīng)商提出。

有關(guān)非 IBM 產(chǎn)品性能的問題應(yīng)當(dāng)向這些產(chǎn)品的供應(yīng)商提出。IBM 公司可能已擁有或正在申請與本說明中描述的內(nèi)容有關(guān)的各項專利。提供本說明并未授予用戶使用這些專利的任何許可。您可以用書面方式將許可查詢寄往: IBM Director of Licensing IBM Corporation North Castle Drive Armonk, NY 10504-1785 U.S.A。所有關(guān)于 IBM 未來方向或意向的聲明都可隨時更改或收回,而不另行通知,它們僅僅表示了目標(biāo)和意愿而已。聯(lián)系您本地的 IBM 辦公人員或者 IBM 授權(quán)的轉(zhuǎn)銷商,以獲得特定的 Statement of General Direction 的全文。

本說明中所包含的信息沒有提交給任何正式的 IBM 測試,而只是“按原樣”發(fā)布。雖然 IBM 可能為了其在特定條件下的精確性而已經(jīng)對每個條目進行了檢查,但不保證在其他地方可以獲得相同的或者類似的結(jié)果。使用此信息或者實現(xiàn)這里所描述的任何技術(shù)是客戶的責(zé)任,取決于客戶評價并集成它們到客戶的操作環(huán)境的能力。嘗試為他們自己的環(huán)境而修改這些技術(shù)的客戶,這樣做所帶來的風(fēng)險由他們自行承擔(dān)。



參考資料

  1. 您可以參閱本文在 developerWorks 全球站點上的 英文原文


作者簡介

 

Nam Keung 是一名高級程序員,他曾致力于 AIX 通信開發(fā)、AIX 多媒體、SOM/DSOM 開發(fā)和 Java 性能方面的工作。他目前的工作包括幫助 ISV 進行應(yīng)用程序設(shè)計、部署應(yīng)用程序、性能調(diào)優(yōu)和關(guān)于 pSeries 平臺的教育。他從 1987 年起就是 IBM 的程序員了。您可以通過 namkeung@us.ibm.com 與 Nam 聯(lián)系。


 

Chakarat Skawratananond 是 IBM eServer Solutions Enablement 組織的一名技術(shù)顧問,在那里,他幫助獨立軟件開發(fā)商在 IBM pSeries 平臺上使用他們的用于 AIX 5L 和 Linux 的應(yīng)用程序。您可以通過 chakarat@us.ibm.com 與他聯(lián)系。

posted on 2009-05-05 16:12 小不懂^_^ 閱讀(342) 評論(0)  編輯 收藏 引用 所屬分類: Windows編程
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            麻豆精品在线视频| 亚洲欧洲久久| 亚洲国产小视频| 好看的日韩视频| 激情亚洲网站| 亚洲韩国青草视频| 在线视频亚洲欧美| 亚洲一区日本| 欧美自拍丝袜亚洲| 农村妇女精品| 亚洲精选在线观看| 欧美亚洲日本网站| 免费一级欧美片在线播放| 欧美日韩免费观看中文| 国产私拍一区| 亚洲精品久久久久久久久| 亚洲在线视频| 欧美bbbxxxxx| 亚洲午夜激情免费视频| 久久久91精品国产一区二区三区 | 亚洲另类在线一区| 亚洲欧美中文另类| 免费久久99精品国产| 国产精品国产福利国产秒拍| 极品少妇一区二区| 亚洲一区二区三区在线观看视频| 羞羞漫画18久久大片| 欧美电影资源| 亚洲欧美视频一区| 欧美精品久久一区二区| 狠狠色丁香婷婷综合| 亚洲一级高清| 亚洲狠狠丁香婷婷综合久久久| 亚洲综合国产激情另类一区| 欧美成人激情视频免费观看| 国模大胆一区二区三区| 亚洲制服av| 亚洲日本一区二区三区| 久久久av水蜜桃| 国产精品揄拍一区二区| 夜夜精品视频| 中国女人久久久| 性伦欧美刺激片在线观看| 欧美电影免费| 亚洲欧美在线播放| 欧美午夜一区二区| 99精品视频免费| 亚洲国产高清aⅴ视频| 久久精品30| 国产婷婷色一区二区三区四区| 亚洲视频精选| 亚洲乱码久久| 欧美日韩国产黄| 亚洲毛片网站| 亚洲国产精品久久人人爱蜜臀 | 久久久av毛片精品| 国产亚洲激情视频在线| 午夜精品美女久久久久av福利| 亚洲美女淫视频| 欧美精品一线| 99精品久久免费看蜜臀剧情介绍| 亚洲国产欧美一区二区三区丁香婷| 麻豆av一区二区三区| 亚洲丰满在线| 91久久精品网| 欧美日韩亚洲另类| 亚洲欧美激情四射在线日| 在线综合+亚洲+欧美中文字幕| 国产精品电影网站| 久久久国产一区二区| 久久精品人人做人人爽| 亚洲第一在线视频| 亚洲黄色在线视频| 国产精品成人观看视频免费| 午夜免费在线观看精品视频| 欧美在线看片| 亚洲国产精品va在线看黑人| 亚洲人体大胆视频| 国产精品亚洲综合久久| 久久久噜噜噜久久狠狠50岁| 免费精品99久久国产综合精品| 亚洲精品一区在线观看| 一区二区三区三区在线| 国产视频欧美| 亚洲精品你懂的| 欧美日韩一区二区三区在线看| 午夜在线电影亚洲一区| 久久一本综合频道| 亚洲一区三区视频在线观看| 欧美一区二区视频在线观看2020| 在线成人性视频| 亚洲剧情一区二区| 国产一区二区在线观看免费| 亚洲国产欧美日韩另类综合| 国产精品一区二区三区乱码| 免费视频最近日韩| 国产精品欧美日韩久久| 欧美国产免费| 国产精品女人网站| 亚洲人成网站色ww在线| 欧美成人亚洲成人日韩成人| 欧美亚洲一级| 亚洲黄色三级| 午夜久久一区| 日韩系列欧美系列| 欧美在线视频一区二区| 99天天综合性| 久久久久久午夜| 亚洲自拍偷拍网址| 欧美精品18+| 蜜臀av在线播放一区二区三区| 欧美亚男人的天堂| 亚洲第一精品夜夜躁人人爽| 黑人巨大精品欧美一区二区| 亚洲一级在线| 亚洲视频精选| 欧美激情在线有限公司| 欧美成人自拍视频| 精品成人久久| 欧美在线视频观看免费网站| 亚洲在线播放电影| 欧美日韩成人在线播放| 欧美激情精品久久久六区热门 | 欧美一级夜夜爽| 欧美日韩国产影院| 欧美激情视频在线播放| 在线观看日韩www视频免费| 欧美在线视频一区二区| 久久精品在线| 国产一区二区中文| 欧美一区二区视频97| 欧美在线中文字幕| 国产欧美日韩视频| 欧美亚洲一区三区| 久久婷婷蜜乳一本欲蜜臀| 国内久久婷婷综合| 久久久久久有精品国产| 欧美jizz19性欧美| 亚洲日本无吗高清不卡| 欧美成人久久| 久久久精品欧美丰满| 国产一级精品aaaaa看| 亚洲在线一区| 欧美亚洲综合在线| 国产婷婷色一区二区三区| 香港久久久电影| 蜜桃精品久久久久久久免费影院| 在线 亚洲欧美在线综合一区| 美女国产精品| 亚洲免费精彩视频| 久久不射中文字幕| 狠狠色狠色综合曰曰| 欧美成人福利视频| 一本一本久久a久久精品综合麻豆 一本一本久久a久久精品牛牛影视 | 亚洲无玛一区| 欧美一区二区免费观在线| 国产日韩在线播放| 久久久一区二区| 亚洲精品乱码久久久久久黑人| 国产精品99久久不卡二区| 国产精品一区二区黑丝| 久久久91精品国产一区二区三区| 亚洲国产成人精品女人久久久| 亚洲天堂av高清| 国产一区二区三区视频在线观看| 免费黄网站欧美| 亚洲一区二区三区久久| 欧美a级一区| 亚洲一区图片| 一区视频在线看| 欧美日韩伊人| 久久久久国产一区二区| 一本大道久久a久久精二百| 久久精品国产综合| 一本色道久久加勒比88综合| 国产色综合久久| 欧美精品啪啪| 久久激情综合| 在线中文字幕不卡| 亚洲国产经典视频| 久久久777| 亚洲私人黄色宅男| 亚洲黄色一区二区三区| 国产噜噜噜噜噜久久久久久久久 | 亚洲影视在线| 亚洲国产精品日韩| 国产精一区二区三区| 欧美日本三区| 免费成人网www| 欧美一区二视频| 亚洲专区免费| 一本色道精品久久一区二区三区| 欧美国产免费| 欧美肥婆在线| 蘑菇福利视频一区播放| 久久久久久久久久看片| 亚洲欧美日韩爽爽影院| 中文在线一区| 一本色道久久综合亚洲精品不| 亚洲国产福利在线|