將 Windows IPC 應用程序移植到 Linux,第 3 部分: 信號

將 Win32 C/C++ 應用程序遷移到 POWER 上的 Linux,第 3 部分: 信號

developerWorks
文檔選項
將此頁作爲電子郵件發送

將此頁作爲電子郵件發送


拓展 Tomcat 應用

下載 IBM 開源 J2EE 應用服務器 WAS CE 新版本 V1.1


級別: 初級

Nam Keung (mailto:[email protected]), 高級程序員, IBM

2005 年 4 月 21 日

將您的 Win32 C/C++ 應用程序遷移到 POWER™ 上的 Linux™,並從信號(semaphore)應用程序接口(application program interface,API)的角度理解 Win32 到 Linux 的映射。Nam Keung 將通過詳細的代碼示例來爲您描述這一過程。

介紹

本系列第三篇文章從信號的角度闡述了 Win32 C/++ 應用程序向 POWER 上的 Linux 的遷移。本系列的第 1 部分介紹了 Win32 API 映射,第 2 部分從互斥(mutex)API 的角度集中闡述瞭如何將 Win32 映射到 Linux。在繼續閱讀之前,建議您先去閱讀本系列的第 1 部分和第 2 部分。





回頁首


信號

信號是包含有一個正數的資源。信號允許進程通過一個單一的原子操作來測試和設置那個整數的值,以此實現同步。通常,信號的主要用途是同步某個線程與其他線程的動作。在多個進程競爭訪問同一操作系統資源時,這也是協調或者同步那些行爲的一種實用技術。

Linux 支持 Portable Operating System Interface(POSIX)信號以及 pthread 條件變量,以此來映射 Win32 信號 API。它們各有其優缺點。您應該基於應用程序的邏輯來判斷使用哪種方法。在映射事件信號的過程中需要考慮的方面包括:

  • 信號的類型:Win32 既支持有名稱的事件信號,也支持無名稱的事件信號。有名稱的信號是在多個進程間共享的。Linux 不支持這種方案。本文中列出的一個進程間通信(Inter-Process Communication,IPC)消息隊列示例代碼將向您展示如何來解決此問題。
  • 初始狀態:在 Win32 中,信號可能會有初始值。在 Linux 中,POSIX 信號支持此功能,但 pthreads 不支持。在使用 pthreads 時您需要考慮到這一點。
  • 超時:Win32 事件信號支持定時等待。在 Linux 中,POSIX 信號實現只支持不確定的等待(阻塞)。pthreads 實現既支持阻塞也支持超時。pthread_cond_timedwait() 調用能給出等待期間的超時的值,pthread_cond_wait() 則用於不確定的等待。
  • 發信號:在 Win32 中,發出信號會喚醒等待那個信號的所有線程。在 Linux 中,POSIX 線程實現一次只喚醒一個線程。pthreads 實現的 pthread_cond_signal() 調用會喚醒一個線程,pthread_cond_broadcast() 調用會向所有等待那個信號的線程發出信號。

 



表 1. 信號映射表
Win32 pthread Linux POSIX
CreateSemaphore pthread_mutex_init(&(token)->mutex, NULL))
pthread_cond_init(&(token)->condition, NULL))
sem_init
CloseHandle (semHandle) pthread_mutex_destroy(&(token->mutex))
pthread_cond_destroy(&(token->condition))
sem_destroy
ReleaseSemaphore(semHandle, 1, NULL) pthread_cond_signal(&(token->condition)) sem_post
WaitForSingleObject(semHandle,
INFINITE)
WaitForSingleObject(semHandle,
timelimit)
pthread_cond_wait(&(token->condition),
&(token->mutex))
pthread_cond_timedwait(&(token
->condition), &(token->mutex))
sem_wait
sem_trywait




回頁首


條件變量

條件變量讓開發者能夠實現一個條件,在這個條件下線程執行然後被阻塞。Microsoft® Win32 接口本身不支持條件變量。爲解決此缺憾,我使用 POSIX 條件變量模擬同步原語,並在一系列文章中對此進行了概述。在 Linux 中,它可以確保因某條件被阻塞的線程,當那個條件改變時,會被解除阻塞。它還允許您原子地(atomically)解除互斥的鎖定,並等待條件變量,而不會有干涉其他線程的可能。不過,每個條件變量都應該伴有一個互斥。前面的表 1 給出了用於線程間同步的 pthread 條件變量。





回頁首


創建信號

在 Win32 中,CreateSemaphore 函數可以創建一個有名稱的或者無名稱的信號對象。Linux 不支持有名稱的信號。



清單 1. 創建信號
HANDLE CreateSemaphore (
	LPSECURITY_ATTRIBUTES	lpSemaphoreAttributes,
	LONG			lInitialCount,
	LONG			lMaximunCount,
	LPCTSTR			lpName
); 

在 Linux 中,sem_init() 調用會創建一個 POSIX 信號:



清單 2. POSIX 信號

					
int sem_init(sem_t *sem, int pshared, unsigned int value

Linux 使用 pthread_condition_init 調用在當前進程內創建信號對象,在其中維持一個在零與最大值之間的計數值。每次有某個線程完成對信號的等待,這個計數值會減小,而每次當某個線程釋放這個信號時,計數值增加。當計數值成爲零時,信號對象的狀態成爲 non-signaled。



清單 3. 創建信號對象的 pthread_condition_init 調用

					
int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);



清單 4. Win32 示例代碼
				
HANDLE semHandle;
semHandle = CreateSemaphore(NULL, 0, 256000, NULL); 
     /* Default security descriptor     */
if( semHandle == (HANDLE) NULL)                     
     /* Semaphore object without a name */
{
     return RC_OBJECT_NOT_CREATED;
}




清單 5. 相應的 Linux 代碼
				
typedef struct 
{
	pthread_mutex_t	mutex;
	pthread_cond_t		condition;
	int			semCount;	
}sem_private_struct, *sem_private;
sem_private    token;
token = (sem_private) malloc(sizeof(sem_private_struct));
if(rc = pthread_mutex_init(&(token->mutex), NULL))
{
	free(token);
	return RC_OBJECT_NOT_CREATED;
}
if(rc = pthread_cond_init(&(token->condition), NULL))
{
	pthread_mutex_destroy( &(token->mutex) );
	free(token);
	return RC_OBJECT_NOT_CREATED;
}
token->semCount = 0;





回頁首


銷燬事件信號

Win32 使用 CloseHandle 來刪除由 CreateSemaphore 所創建的信號對象。



清單 6. 銷燬事件信號
BOOL CloseHandle (HANDLE hObject);

Linux POSIX 信號使用 sem_destroy() 來銷燬無名稱的信號。



清單 7. sem_destroy()
				
int sem_destroy(sem_t *sem);

在 Linux pthreads 中,使用 pthread_cond_destroy() 來銷燬條件變量。



清單 8. pthread_cond_destroy()

					
int pthread_cond_destroy(pthread_cond_t *cond);



清單 9. Win32 代碼和相應的 Linux 代碼
Win32 代碼 相應的 Linux 代碼
CloseHandle(semHandle); pthread_mutex_destroy(&(token->mutex));

pthread_cond_destroy(&(token->condition));

free (token);




回頁首


發佈事件信號

在 Win32 中,ReleaseSemaphore 函數會令指定的信號對象的計數值增加指定數量。



清單 10. ReleaseSemaphore 函數

					
BOOL ReleaseSemaphore(
	HANDLE hSemaphore,
	LONG 	lReleaseCount,
	LPLONG	lpPreviousCount
);

Linux POSIX 信號使用 sem_post() 來發布事件信號。這將喚醒阻塞於此信號的所有線程。



清單 11. sem_post()

					
int sem_post(sem_t * sem);

在 Linux 中,pthread_cond_signal 會喚醒等待某個條件變更的某個線程。Linux 調用這個函數來爲此對象所標識的信號發佈一個事件完成信號。調用的線程增加那個信號的值。如果信號的值從零開始增加,而且 pthread_cond 中有任何線程被阻塞,那麼請等待這個信號,因爲其中一個會被喚醒。默認情況下,實現可以選擇任意的正在等待的線程。



清單 12. pthread_cond_signal

					
int pthread_cond_signal(pthread_cond_t *cond);



清單 13. Win32 代碼和相應的 Linux 代碼
Win32 代碼 相應的 Linux 代碼
ReleaseSemaphore(semHandle, 1, NULL) if (rc = pthread_mutex_lock(&(token->mutex)))
return RC_SEM_POST_ERROR;

token->semCount ++;

if (rc = pthread_mutex_unlock(&(token->mutex)))
return RC_SEM_POST_ERROR;

if (rc = pthread_cond_signal(&(token->condition)))
return RC_SEM_POST_ERROR;




回頁首


等待事件信號

Win32 調用 WaitForSingleObject 函數來等待所需要的信號上事件的完成。當等待單一線程同步對象時,可以使用此方法。當對象被設置發出信號或者超時時間段結束時,這個方法會得到通知。如果時間間隔是 INFINITE,那麼它就會無止境地等待下去。



清單 14. WaitForSingleObject 函數

					
DWORD WaitForSingleObject(
	HANDLE hHANDLE,
	DWORD	dwMilliseconds
);

使用 WaitForMultipleObjects 函數來等待多個被通知的對象。在信號線程同步對象中,當計數器變爲零時,對象是 non-signaled。



清單 15. WaitForMultipleObjects 函數

					
DWORD WaitForMultipleObjects(
	DWORD	nCount,
	Const	HANDLE* lpHandles,
	BOOL	bWaitAll,
	DWORD	dwMilliseconds
);

Linux POSIX 信號使用 sem_wait() 來掛起發出調用的線程,直到信號擁有了非零的計數值。然後它自動地減少信號的計數值。



清單 16. sem_wait() 函數

					
int sem_wait(sem_t * sem);

在 POSIX 信號中不能使用超時選項。不過,您可以通過在某個循環中執行非阻塞的 sem_trywait() 來完成此功能,它會計算超時的值。



清單 17. sem_trywait() 函數

					
int sem_trywait(sem_t  * sem);

在 Linux 中,pthread_cond_wait() 會阻塞發出調用的線程。發出調用的線程會減小那個信號。如果當 pthread_cond_wait 被調用時信號是零,則 pthread_cond_wait() 就會阻塞,直到另一個線程增加了那個信號的值。



清單 18. pthread_cond_wait() 函數

					
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t  *mutex);

pthread_cond_wait 函數首先釋放相關聯的 external_mutex of type pthread_mutex_t,當調用者檢查條件表達式時必須持有它。



清單 19. Win32 代碼和相應的 Linux 代碼
Win32 代碼 相應的 Linux 代碼
DWORD retVal;

retVal = WaitForSingleObject(semHandle, INFINITE);

if (retVal == WAIT_FAILED) return RC_SEM_WAIT_ERROR
if (rc = pthread_mutex_lock(&(token->mutex)))
return RC_SEM_WAIT_ERROR;

while (token->semCount <= 0)
{
rc = pthread_cond_wait(&(token->condition), &(token->mutex));
if (rc &&errno != EINTR )
break;
}
token->semCount--;

if (rc = pthread_mutex_unlock(&(token->mutex)))
return RC_SEM_WAIT_ERROR;

如果您需要在指定的一段時間內阻塞發出調用的線程,那麼請使用 pthread_cond_timewait 來阻塞它。調用這個方法來等待所需要信號上某個事件的完成,等待指定的一段時間。



清單 20. pthread_cond_timewait
				
	int pthread_cond_timewait(
	pthread_cond_t		*cond,
	pthread_mutex_t		*mutex,
	timespec		*tm
);			





清單 21. Win32 代碼和相應的 Linux 代碼
Win32 代碼 相應的 Linux 代碼
retVal = WaitForSingleObject(SemHandle, timelimit);

if (retVal == WAIT_FAILED)
return RC_SEM_WAIT_ERROR;

if (retVal == WAIT_TIMEOUT)
return RC_TIMEOUT;
int rc;
struct timespec tm;
struct timeb tp;
long sec, millisec;

if (rc = pthread_mutex_lock(&(token->mutex)))
return RC_SEM_WAIT_ERROR;

sec = timelimit / 1000;
millisec = timelimit % 1000;
ftime( &tp );
tp.time += sec;
tp.millitm += millisec;
if( tp.millitm > 999 )
{
tp.millitm -= 1000;
tp.time++;
}
tm.tv_sec = tp.time;
tm.tv_nsec = tp.millitm * 1000000 ;

while (token->semCount <= 0)
{
rc = pthread_cond_timedwait(&(token->condition), &(token->mutex), &tm);
if (rc && (errno != EINTR) )
break;
}
if ( rc )
{
if ( pthread_mutex_unlock(&(token->mutex)) )
return RC_SEM_WAIT_ERROR );

if ( rc == ETIMEDOUT) /* we have a time out */
return RC_TIMEOUT );

return RC_SEM_WAIT_ERROR );

}
token->semCount--;

if (rc = pthread_mutex_unlock(&(token->mutex)))
return RC_SEM_WAIT_ERROR;




回頁首


POSIX 信號示例代碼

清單 22 使用 POSIX 信號來實現線程 A 和 B 之間的同步:



清單 22. POSIX 信號示例代碼

					
sem_t sem; /* semaphore object */
int irc;   /* return code */
/* Initialize the semaphore - count is set to 1*/
irc = sem_init (sem, 0,1)
...
/* In Thread A */
/* Wait for event to be posted */
sem_wait (&sem);
/* Unblocks immediately as semaphore initial count was set to 1 */
 .......
/* Wait again for event to be posted */
sem_wait (&sem);
/* Blocks till event is posted */
/* In Thread B */
/* Post the semaphore */
...
irc = sem_post (&sem);
/* Destroy the semaphore */
irc = sem_destroy(&sem);





回頁首


進程內信號示例代碼



清單 23. Win32 進程內信號示例代碼
				
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
void thrdproc      (void   *data);  // the thread procedure (function) 
     to be executed
HANDLE   semHandle;
int
main( int argc, char **argv )
{
        HANDLE    *threadId1;
        HANDLE    *threadId2;
        int        hThrd;
        unsigned   stacksize;
        int	    arg1;
	if( argc < 2 )
		arg1 = 7;
	else
		arg1 = atoi( argv[1] );
	printf( "Intra Process Semaphor test./n" );
	printf( "Start./n" );
	semHandle = CreateSemaphore(NULL, 1, 65536, NULL);
        if( semHandle == (HANDLE) NULL)
	{
		printf("CreateSemaphore error: %d/n", GetLastError());
	}
	printf( "Semaphor created./n" );
	
        if( stacksize < 8192 )
            stacksize = 8192;
        else
            stacksize = (stacksize/4096+1)*4096;
     
        hThrd = _beginthread( thrdproc, // Definition of a thread entry
                                  NULL,
                             stacksize,
                            "Thread 1");
        if (hThrd == -1)
            return RC_THREAD_NOT_CREATED);
        *threadId1 = (HANDLE) hThrd;
         hThrd = _beginthread( thrdproc, // Definition of a thread entry
                                   NULL,
                              stacksize,
                              “Thread 2");
         if (hThrd == -1)
            return RC_THREAD_NOT_CREATED);
         *threadId2 = (HANDLE) hThrd;
	 printf( "Main thread sleeps 5 sec./n" );
         sleep(5);
         if( ! ReleaseSemaphore(semHandle, 1, NULL) )
		printf("ReleaseSemaphore error: %d/n", GetLastError());
         printf( "Semaphor released./n" );
         printf( "Main thread sleeps %d sec./n", arg1 );
	
         sleep (arg1);
       if( ! ReleaseSemaphore(semHandle, 1, NULL) )
		printf("ReleaseSemaphore error: %d/n", GetLastError());
 
	printf( "Semaphor released./n" );
	printf( "Main thread sleeps %d sec./n", arg1 );
	sleep (arg1);
        CloseHandle(semHandle);
	
	printf( "Semaphor deleted./n" );
	printf( "Main thread sleeps 5 sec./n" );
        
        sleep (5);
        printf( "Stop./n" );
	return OK;
}
void
thread_proc( void *pParam )
{
 
 DWORD  retVal;
	printf( "/t%s created./n", pParam );
	       
        retVal = WaitForSingleObject(semHandle, INFINITE);
        if (retVal == WAIT_FAILED)
               return RC_SEM_WAIT_ERROR;
	printf( "/tSemaphor blocked by %s. (%lx)/n", pParam, retVal);
	printf( "/t%s sleeps for 5 sec./n", pParam );
	sleep(5);
	if( ! ReleaseSemaphore(semHandle, 1, NULL) )
                printf("ReleaseSemaphore error: %d/n", GetLastError());
	printf( "/tSemaphor released by %s.)/n", pParam);
}





清單 24. 相應的 Linux 進程內信號示例代碼
				
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <pthread.h>
#include <errno.h>
void  thread_proc (void * data);
pthread_mutexattr_t     attr;
pthread_mutex_t         mutex;
typedef struct
{
        pthread_mutex_t         mutex;
        pthread_cond_t          condition;
        int                     semCount;
}sem_private_struct, *sem_private;
sem_private     token;
int main( int argc, char **argv )
{
        pthread_t             threadId1;
        pthread_t             threadId2;
        pthread_attr_t        pthread_attr;
        pthread_attr_t        pthread_attr2;
        int			arg1;
        int                   rc;
	if( argc < 2 )
		arg1 = 7;
	else
		arg1 = atoi( argv[1] );
      printf( "Intra Process Semaphor test./n" );
      printf( "Start./n" );
      token =(sem_private)  malloc (sizeof (sem_private_struct));        
     
      if(rc = pthread_mutex_init( &(token->mutex), NULL))
      {
                free(token);
                return 1;
      }
      if(rc = pthread_cond_init(&(token->condition), NULL))
      {
           printf( "pthread_condition ERROR./n" );
           pthread_mutex_destroy( &(token->mutex) );
           free(token);
           return 1;
      }
      token->semCount = 0;
      printf( "Semaphor created./n" );
      if (rc = pthread_attr_init(&pthread_attr))
      {
           printf( "pthread_attr_init ERROR./n" );
           exit;
      }
      if (rc = pthread_attr_setstacksize(&pthread_attr, 120*1024))
      {
           printf( "pthread_attr_setstacksize ERROR./n" );
           exit;
      }
      if (rc = pthread_create(&threadId1,
                           &pthread_attr,
            (void*(*)(void*))thread_proc, 
                               "Thread 1" ))
      {
           printf( "pthread_create ERROR./n" );
           exit;
      }
      if (rc = pthread_attr_init(&pthread_attr2))
      {
           printf( "pthread_attr_init2 ERROR./n" );
           exit;
      }
      if (rc = pthread_attr_setstacksize(&pthread_attr2, 120*1024))
      {
           printf( "pthread_attr_setstacksize2 ERROR./n" );
           exit;
      }
      if (rc = pthread_create(&threadId2, 
                          &pthread_attr2,
            (void*(*)(void*))thread_proc,
                               "Thread 2" ))
      {
           printf( "pthread_CREATE ERROR2./n" );
           exit ;  // EINVAL, ENOMEM
      }
	
      printf( "Main thread sleeps 5 sec./n" );
      sleep( 5 );
      if (rc =  pthread_mutex_lock(&(token->mutex)))
      {
           printf( "pthread_mutex_lock ERROR 1./n" );
           return 1; 
      }
      token->semCount ++;
      if (rc = pthread_mutex_unlock&(token->mutex)))
      {
           printf( "pthread_mutex_unlock ERROR 1./n" );
           return 1; 
      }
      if (rc = pthread_cond_signal(&(token->condition)))
      {
           printf( "pthread_cond_signal ERROR1./n" );
           return 1; 
      }
      printf( "Semaphor released./n" );
      printf( "Main thread sleeps %d sec./n", arg1 );
      sleep( arg1 );
      if (rc =  pthread_mutex_lock(&(token->mutex)))
      {
           printf( "pthread_mutex_lock ERROR./n" );
           return 1; 
      }
      token->semCount ++;
      if (rc = pthread_mutex_unlock(&(token->mutex)))
      {
           printf( "pthread_mutex_lock ERROR./n" );
           return 1; 
      }
      if (rc = pthread_cond_signal(&(token->condition)))
      {
           printf( "pthread_cond_signal ERROR./n" );
           return 1; 
      }
	
      printf( "Semaphor released./n" );
      printf( "Main thread sleeps %d sec./n", arg1 );
      sleep( arg1 );
      pthread_mutex_destroy(&(token->mutex));
      pthread_cond_destroy(&(token->condition));	
      printf( "Semaphor deleted./n" );
      printf( "Main thread sleeps 5 sec./n" );
      sleep( 5 );
      printf( "Stop./n" );
      return 0;
}
void
thread_proc( void *pParam )
{
 int	rc;
      printf( "/t%s created./n", pParam );
      if (token == (sem_private) NULL)
          return ;
      if (rc =  pthread_mutex_lock(&(token->mutex)))
      {
           printf( "pthread_mutex_lock ERROR2./n" );
           return ; 
      }
      while (token->semCount <= 0)
      {
                rc = pthread_cond_wait(&(token->condition), &(token->mutex));
                if (rc && errno != EINTR )
                        break;
      }
      if( rc )
      {
                pthread_mutex_unlock(&(token->mutex));
                printf( "pthread_mutex_unlock ERROR3./n" );
                return; 
      }
      token->semCount--;
      if (rc = pthread_mutex_unlock(&(token->mutex)))
      {
           printf( "pthread_mutex_lock ERROR./n" );
           return ; 
      }
      printf( "/tSemaphor blocked by %s. (%lx)/n", pParam, rc );
      printf( "/t%s sleeps for 5 sec./n", pParam );
      sleep( 5 );
      if (rc =  pthread_mutex_lock(&(token->mutex)))
      {
           printf( "pthread_mutex_lock ERROR./n" );
           return ; 
      }
      token->semCount ++;
      if (rc = pthread_mutex_unlock(&(token->mutex)))
      {
           printf( "pthread_mutex_unlock ERROR./n" );
           return ; 
      }
      if (rc = pthread_cond_signal(&(token->condition)))
      {
           printf( "pthread_cond_signal ERROR./n" );
           return ; 
      }
      printf( "/tSemaphor released by %s. (%lx)/n", pParam, rc );





回頁首


進程間信號示例代碼



清單 25. Win32 進程間信號示例代碼,進程 1
				
#include <stdio.h>
#include <windows.h>
#define WAIT_FOR_ENTER  printf( "Press ENTER/n" );getchar()
int main()
{
       HANDLE		semaphore;
       int		nRet;
       DWORD          retVal;
       SECURITY_ATTRIBUTES		sec_attr;
	printf( "Inter Process Semaphore test - Process 1./n" );
	printf( "Start./n" );
	
	sec_attr.nLength              = sizeof( SECURITY_ATTRIBUTES );
	sec_attr.lpSecurityDescriptor = NULL;
	sec_attr.bInheritHandle       = TRUE;
	semaphore = CreateSemaphore( &sec_attr, 1, 65536, “456789" );
	if( semaphore == (HANDLE) NULL )
		return RC_OBJECT_NOT_CREATED;
       printf( "Semaphore created. (%lx)/n", nRet );
	
	WAIT_FOR_ENTER;
	
	if( ! ReleaseSemaphore(semaphore, 1, NULL) )
		return SEM_POST_ERROR;
      
       printf( "Semaphore Posted. /n");
	
	WAIT_FOR_ENTER;
	retVal = WaitForSingleObject (semaphore, INFINITE );
        if (retVal == WAIT_FAILED)
              return SEM_WAIT_ERROR;
  
	printf( "Wait for Semaphore. /n");
	
       WAIT_FOR_ENTER;
	       
       CloseHandle (semaphore);
	printf( "Semaphore deleted./n" );
	printf( "Stop./n" );
	return 0;
}

清單 26 給出了作爲支持進程間共享的有名稱信號示例的消息 IPC 代碼。



清單 26. 相應的 Linux 進程間信號示例代碼,進程 1
				
#include <stdio.h>
#include <sys/types.h>
#include <sys/sem.h>
#include <sys/stat.h>
#include <errno.h>
#include <unistd.h>
#define WAIT_FOR_ENTER  printf( "Press ENTER/n" );getchar()
struct msgbuf {
        long mtype;         /* type of message */
        char mtext[1];      /* message text */
};
int main()
{
        key_t           msgKey;
        int             flag;
        struct msgbuf   buff;
        int             sem;
        int             nRet =0;
	printf( "Inter Process Semaphore test - Process 1./n" );
	printf( "Start./n" );
        
	flag = IPC_CREAT|IPC_EXCL;
      if( ( msgKey = (key_t) atol( "456789" ) ) <= 0 )
                return 1;
      flag |= S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
      sem  = (int) msgget( msgKey, flag );
      
      if (sem == -1)
             if( errno == EEXIST )
             {
                    flag &= ~IPC_EXCL;
                    sem = (int) msgget( msgKey, flag );
                    if (msgctl(sem, IPC_RMID, NULL ) != 0)
                            return 1;
                    sem = (int) msgget( msgKey, flag );
                    if (sem == -1)
                            return 1;
             }
             else
                    return 1;
      printf( "Semaphore created. /n" );
      WAIT_FOR_ENTER;
      buff.mtype = 123;
      if( msgsnd( sem, &buff, 1, 0 ) < 0 )
          return 1;
      printf( "Semaphore Posted. /n" );
	
      WAIT_FOR_ENTER;
      if( msgrcv( sem, &buff, 1, 0, 0 ) < 0 )
          return 1;
      printf( "Wait for Semaphore. /n" );
      WAIT_FOR_ENTER;
      msgctl(sem, 0, IPC_RMID );
      printf( "Semaphore deleted./n" );
	printf( "Stop./n" );
	return 0;
}





清單 27. Win32 進程間信號示例代碼,進程 2
				
#include <stdio.h>
#include <windows.h>
int main()
{
	HANDLE	semaphore;
	DWORD   retVal;
	printf( "Inter Process Semaphore test - Process 2./n" );
	printf( "Start./n" );
	SECURITY_ATTRIBUTES		sec_attr;
       
       sec_attr.nLength              = sizeof( SECURITY_ATTRIBUTES );
       sec_attr.lpSecurityDescriptor = NULL;
       sec_attr.bInheritHandle       = TRUE;
	semaphore = CreateSemaphore( &sec_attr, 0, 65536, “456789" );
	if( semaphore == (HANDLE) NULL )
		return RC_OBJECT_NOT_CREATED;
	printf( "Semaphore opened. (%lx)/n", nRet );
	
	printf( "Try to wait for semaphore./n" );
	
       while( ( retVal = WaitForSingleObject( semaphore, 250 ) ) == WAIT_TIMEOUT)
		printf( "Timeout. /n");
	
       printf( "Semaphore acquired. /n");
       printf( "Try to post the semaphore./n" );
	       
       if( ! ReleaseSemaphore(semaphore, 1, NULL) )
	     return RC_SEM_POST_ERROR;
	
       printf( "Semaphore posted. /n");
	
	CloseHandle(semaphore);
	printf( "Semaphore closed. /n");
	printf( "Stop./n" );
	return 0;
}





清單 28. 相應的 Linux 進程間信號示例代碼,進程 2
				
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/sem.h>
#include <sys/stat.h>
#include <errno.h>
#include <unistd.h>
#define RC_TIMEOUT = 3
struct msgbuf {
        long mtype;         /* type of message */
        char mtext[1];      /* message text */
};
int main()
{
        key_t           msgKey;
        int             flag=0;
        struct msgbuf   buff;
        int             sem;
        int             nRet =0;
	printf( "Inter Process Semaphore test - Process 2./n" );
	printf( "Start./n" );
      if( ( msgKey = (key_t) atol( "456789" ) ) <= 0 )
            return 1;
      flag |= S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
      sem = (int) msgget( msgKey, flag );
      if (sem == -1)
            if( errno == EEXIST )
            {
                   flag &= ~IPC_EXCL;
                   sem = (int) msgget( msgKey, flag );
                   if (msgctl(sem, IPC_RMID, NULL ) != 0)
                          return 1;
                   sem = (int) msgget( msgKey, flag );
                   if (sem == -1)
                           return 1;
            }
            else
                   return 1;
	printf( "Semaphore opened. (%lx)/n", nRet );
	if( nRet != 0 )
          return 0;
	printf( "Try to wait for semaphore./n" );
	while( ( nRet = sem_shared_wait_timed( sem, 250 ) ) == 3) 
	
	printf( "Timeout. (%lx)/n", nRet );
	printf( "Semaphore acquired. (%lx)/n", nRet );
	printf( "Try to post the semaphore./n" );
       buff.mtype = 123;
       if( msgsnd( sem, &buff, 1, 0 ) < 0 )
          return 1;
	printf( "Semaphore posted. (%lx)/n", nRet );
	if( nRet != 0 )
		return 0;
	printf( "Semaphore closed. (%lx)/n", nRet );
	printf( "Stop./n" );
	return 0;
}
int sem_shared_wait_timed( int sem, unsigned long timelimit)
{
        struct msgbuf           buff;
        struct timeval          timeOut;
        int                     msg[1];
        int                     nRet=0;
        timeOut.tv_sec  = timelimit / 1000;
        timeOut.tv_usec = (timelimit % 1000) * 1000;
        msg[0] = sem;
        nRet = select( 0x1000, (fd_set *)msg, NULL, NULL, &timeOut );
        if(nRet == 0)
           return 3;
        if( msgrcv( sem, &buff, 1, 0, 0 ) < 0 )
              return 1;
}





回頁首


結束語

本系列的第三篇文章從信號 API 的角度講述了從 Win32 到 Linux 的映射,並給出了您可以引用的信號示例代碼。線程化的、同步的系統所提出的挑戰不僅是設計與實現,也包括了質量保證的所有階段。當進行從 Win32 到 Linux 的遷移時,可以將這些文章做爲參考。一定要去閱讀本系列中以前的文章。

補充聲明

Microsoft、Windows、Windows NT 和 Windows 徽標是 Microsoft Corporation 在美國和/或其他國家或地區的商標或註冊商標。

Intel、Intel Inside(logos)、MMX 和 Pentium 是 Intel 公司在美國和/或其他國家或地區的商標。

UNIX 是 The Open Group 在美國和其他國家或地區的註冊商標。

Linux 是 Linus Torvalds 在美國和/或其他國家或地區的商標。



參考資料



關於作者

 

Nam Keung 是 IBM 的一名高級程序員,他曾致力於 AIX 通信開發、AIX 多媒體、SOM/DSOM 開發和 Java 性能方面的工作。他目前的工作包括幫助獨立軟件提供商(Independent Software Vendors,ISV)進行應用程序設計、部署應用程序、性能調優和關於 pSeries 平臺的教育。您可以通過 [email protected] 與 Nam 聯繫。

 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章