• <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>

            C++樂園

            C/C++ 交流

              C++博客 :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
              12 隨筆 :: 18 文章 :: 14 評論 :: 0 Trackbacks
            ? 將 Win32 C/C++ 應(yīng)用程序遷移到 POWER 上的 Linux,第 1 部分: 進(jìn)程、線程和共享內(nèi)存服務(wù) (轉(zhuǎn)載)
            特別是進(jìn)程、線程和共享內(nèi)存服務(wù))到 POWER 上 Linux 的映射。本文可以幫助您確定哪種映射服務(wù)最適合您的需要。作者向您詳細(xì)介紹了他在移植 Win32 C/C++ 應(yīng)用程序時(shí)遇到的 API 映射。

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

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

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

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

            在 Linux 上,GCC 有一個(gè)擴(kuò)展,允許指定當(dāng)可執(zhí)行文件或者包含它的共享對象啟動或停止時(shí)應(yīng)該調(diào)用某個(gè)函數(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 */}      

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

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

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

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

            進(jìn)程映射表

            Win32Linux
            CreateProcessfork()
            execv()
            TerminateProcesskill
            ExitProcess() exit()
            GetCommandLineargv[]
            GetCurrentProcessIdgetpid
            KillTimeralarm(0)
            SetEnvironmentVariableputenv
            GetEnvironmentVariablegetenv
            GetExitCodeProcesswaitpid

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

            Win32 examplePROCESS_INFORMATION    procInfo;STARTUPINFO	        startupInfo;typedef DWORD          processId;char                   *exec_path_namechar                   *_cmd_line;        GetStartupInfo( &startupInfo );     // You must fill in this structureif( 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 中,進(jìn)程 ID 是一個(gè)整數(shù)。Linux 中的搜索目錄由 PATH 環(huán)境變量(exec_path_name)決定。 fork() 函數(shù)建立父進(jìn)程的一個(gè)副本,包括父進(jìn)程的數(shù)據(jù)空間、堆和棧。 execv() 子例程使用 exec_path_name 將調(diào)用進(jìn)程當(dāng)前環(huán)境傳遞給新的進(jìn)程。

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

            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;}      

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

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

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

            Win32 sample codeif( thread != (HANDLE) NULL ){    HANDLE	thread_dup;    if( DuplicateHandle( OpenProcess(PROCESS_ALL_ACCESS, TRUE,  processId),                                     thread,                                     GetCurrentProcess(),                                     &amp;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 信號來終止特定進(jìn)程(processId)。然后調(diào)用設(shè)置 WNOHANG 位的 waitpid 子例程。這將檢查特定的進(jìn)程并終止。

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

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

            Win 32 sampleHANDLE      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)指定的特定進(jìn)程。Signal 參數(shù)是一個(gè) null 值,會執(zhí)行錯(cuò)誤檢查,但不發(fā)送信號。

            Equivalent Linux codeif ( 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 時(shí)間的基本單位;當(dāng)?shù)却{(diào)度時(shí),每個(gè)線程保持信息來保存它的“上下文”。每個(gè)線程都可以執(zhí)行程序代碼的任何部分,并共享進(jìn)程的全局變量。

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

            對有外加 LinuxThreads 的信號處理來說,每個(gè)線程都會繼承信號處理器(如果派生這個(gè)線程的父進(jìn)程注冊了一個(gè)信號處理器的話。只有在 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)前的新線程。

            線程映射表

            Win32Linux
            _beginthreadpthread_attr_init
            pthread_attr_setstacksize
            pthread_create
            _endthreadpthread_exit
            TerminateThread pthread_cancel
            GetCurrentThreadIdpthread_self

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

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

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

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

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

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

            Win32 sampleint		hThrd;DWORD          dwIDThread;unsigned       stacksize;void           *thrdparam; //parameter to be passed to the thread when it                                   //begins executionHANDLE         *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 parametervoid        *thrdparam; //parameter to be passed to the thread when it                                //begins executionpthread_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 中,一個(gè)線程可以使用 TerminateThread 函數(shù)終止另一個(gè)線程。不過,線程的棧和其他資源將不會被收回。如果線程終止自己,則這樣是可取的。在 Linux 中,pthread_cancel 可以終止由具體的 threadId 所標(biāo)識的線程的執(zhí)行。

            Win32Linux
            TerminateThread((HANDLE *) threadId, 0); pthread_cancel(threadId);

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

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

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

            Win32Linux
            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() 來退出一個(gè)線程,以避免顯式地調(diào)用 exit 例程。在 Linux 中,線程的返回值是 retval,可以由另一個(gè)線程調(diào)用 pthread_join() 來獲得它。

            Win32Linux
            _endthread(); pthread_exit(0);

            獲得當(dāng)前線程 ID 服務(wù)
            在 Win32 進(jìn)程中,GetCurrentThreadId 函數(shù)獲得進(jìn)行調(diào)用的線程的線程標(biāo)識符。Linux 使用 pthread_self() 函數(shù)來返回進(jìn)行調(diào)用的線程的 ID。

            Win32Linux
            GetCurrentThreadId()pthread_self()

            sleep 服務(wù)

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

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

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

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

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

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

            Win32Linux
            SleepEx (0,0)sched_yield()

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

            一個(gè)典型的使用情形是:

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

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

            Win32Linux
            CreateFileMaping,
            OpenFileMapping
            mmap
            shmget
            UnmapViewOfFilemunmap
            shmdt
            MapViewOfFilemmap
            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ù)也可以在多個(gè)進(jìn)程和線程之間共享。不過,這需要進(jìn)程或線程之間同步,由應(yīng)用程序來處理。

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

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

            Win32Linux
            PAGE_READONLYPROT_READ
            PAGE_READWRITE(PROT_READ | PROT_WRITE)
            PAGE_NOACCESSPROT_NONE
            PAGE_EXECUTEPROT_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)存的一個(gè)示例:

            echo 524288000 > /proc/sys/kernel/shmmax
            最大共享內(nèi)存增加到 500 MB。

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

            Win32 sample codetypedef 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ū)域的映射。如果某個(gè)區(qū)域內(nèi)的一個(gè)地址被 mmap 子例程取消映射,并且那個(gè)區(qū)域后來未被再次映射,那么任何對那個(gè)地址的引用將導(dǎo)致給進(jìn)程發(fā)出一個(gè) SIGSEGV 信號。

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

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

            close(token->nFileDes);

            remove(token->pFileName);

            free(token->pFileName);

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



            Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=465925

            posted on 2007-01-18 11:28 小不懂^_^ 閱讀(170) 評論(0)  編輯 收藏 引用

            只有注冊用戶登錄后才能發(fā)表評論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


            久久国产精品无码一区二区三区 | 中文成人久久久久影院免费观看| 72种姿势欧美久久久久大黄蕉| 亚洲中文字幕久久精品无码APP| 久久精品国产2020| 久久精品亚洲日本波多野结衣| 伊人色综合久久天天人手人婷| 国产午夜免费高清久久影院| 国产精品99久久久久久宅男| 久久综合给合综合久久| 久久久久亚洲精品日久生情 | 国产精品女同久久久久电影院| 久久电影网一区| 国产精品久久久久蜜芽| 欧美午夜精品久久久久免费视| AA级片免费看视频久久| 亚洲国产精品无码久久久蜜芽 | 久久久国产视频| 亚洲综合精品香蕉久久网97| 综合久久精品色| 国产精品九九久久免费视频 | 久久人人爽人人爽人人片AV东京热| 国产精品免费看久久久| 久久久久久伊人高潮影院| 国产精品狼人久久久久影院| 精品无码久久久久国产| 久久亚洲AV成人无码| 久久精品国产99久久丝袜| 91精品国产9l久久久久| 精品久久久中文字幕人妻| 久久久久久国产精品免费免费| 国产欧美一区二区久久| 熟妇人妻久久中文字幕| 一本久久免费视频| 理论片午午伦夜理片久久| 伊人久久大香线蕉影院95| 久久天天躁狠狠躁夜夜avapp| 国产美女亚洲精品久久久综合| 中文字幕亚洲综合久久菠萝蜜| 亚洲午夜精品久久久久久浪潮| 亚洲人成网站999久久久综合|