设为首页 收藏本站
查看: 370|回复: 0

[经验分享] Migrate Win32 C/C++ application to Linux on POWER, Part 2: Mutexes

[复制链接]

尚未签到

发表于 2015-12-10 08:52:46 | 显示全部楼层 |阅读模式
http://www.ibm.com/developerworks/systems/library/es-win32linux.html

This series of articles helps you migrate your Win32 C/C++applications to Linux on POWER. Senior programmer Nam Keung and pSeries?Linux technical consultant Chakarat Skawratananond illustrate how to map Win32to Linux with respect to mutex application program interfaces (APIs). Part 1 of this series focused on Win32 APImapping.

Introduction
  This article focuses on mutex primitives. You are encouraged to review thefollowing sections in Part 1 of this series before continuing:

  • Initialization
  • Process
  • Threads
  • Shared memory

Mutexes
  A mutex provides exclusive access control for a resource between threads,as shown in Table 1 below. It is a simple lock withonly the thread that owns the lock being able to release the mutex. Itensures the integrity of a shared resource that they access (most commonlyshared data), by allowing only one thread to access it at a time.
Table 1.MutexesWin32LinuxCreateMutex(0, FALSE, 0);pthread_mutex_init(&mutex, NULL))CloseHandle(mutex);pthread_mutex_destroy(&mutex)WaitForSingleObject(mutex, INFINITE))pthread_mutex_lock(&mutex)ReleaseMutex(mutex);pthread_mutex_unlock(&mutex)  Back to top
Create a mutex
  In Win NT/Win2K, all mutexes are recursive.
  In Win32, CreateMutex() provides exclusive access control fora resource between threads within the current process. This method enablesthreads to serialize their access to the resources within a process. Oncethe mutual exclusion handle is created, it?’s available to allthreads in the current process (see Listing 1 below).
Listing 1. Create amutex

HANDLE CreateMutex(
LPSECURITY_ATTRIBUTESlMutexAttributes,
BOOLlInitialOwner,
LPCTSTRlName
)
  Linux uses the pthread library call, pthread_mutex_init(), tocreate the mutex, as shown in Listing 2 below.
Listing 2.pthread

int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr);
  Linux has three kinds of mutex. The mutex kind determines what happens if athread attempts to lock a mutex it already owns in apthread_mutex_lock:
Fast mutex: While trying to lock the mutex using the pthread_mutex_lock(), the calling thread is suspendedforever.Recursive mutex:pthread_mutex_lock() immediately returns with a successreturn code.Error check mutex: pthread_mutex_lock() immediately returns with the errorcode EDEADLK.  The mutex kind can be set in two ways. Listing 3 illustrates a static way of setting a mutex.
Listing 3. Static way forsetting amutex

/* For Fast mutexes */
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

/* For recursive mutexes */
  You can lock a mutex with the function: pthread_mutex_lock(pthread_mutex_t *mutex). This functiongets a pointer to the mutex it is trying to lock. The function returnswhen the mutex is locked, or if an error occurred. The error is not due tothe locked mutex. The function waits until the mutex becomes unlocked.
  Another way of setting the mutex kind is by using a mutex attribute object.To do this, pthread_mutexattr_init() is called to initializethe object followed by a pthread_mutexattr_settype(), whichsets the kind of mutex, as shown in Listing 4 below.
Listing 4. Setting a mutexbyattribute

int pthread_mutexattr_init(pthread_mutexattr_t *attr);
int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int kind);
  A mutex is unlocked with the function (see Listing5):
  Here's the sample code for creating a mutex (see Listings 6 and 7 below).
Listing 5. The unlockfuction

pthread_mutex_unlock(pthread_mutex_t *mutex))
Listing 6. Win32 samplecode

HANDLE mutex;

mutex = CreateMutex(0, FALSE, 0);
if (!(mutex))
{
return RC_OBJECT_NOT_CREATED;
}
Listing 7. Equivalent Linuxcode

pthread_mutexattr_t  attr;
pthread_mutex_t      mutex;

pthread_mutexattr_init (&attr);
if (rc = pthread_mutex_init(&mutex, &attr))
{
return RC_OBJECT_NOT_CREATED;
}
  Back to top
Destroying a mutex
  In Win32, the CloseHandle() method (see Listing 8) deletes an object to provide an exclusive accesscontrol for a resource within a current process. After the deletion of theobject, the mutex object is invalid until the CloseHandle() method initializes it again by calling CreateMutex.
  Once there is no longer an exclusive access for a resource, you shoulddestroy it by calling this method. If you need to relinquish the ownershipof the object, the ReleaseMutex() method should becalled.
  The pthread_mutex_destroy() in Linux destroys a mutex object,which frees the resources it might hold. It also checks whether the mutexis unlocked at that time (see Listing 9).
Listing 8. Win32 samplecode

if(WaitForSingleObject(mutex, (DWORD)0) == WAIT_TIMEOUT )
return RC_NOT_OWNER;

CloseHandle(mutex);
Listing 9. Linuxcode

if (pthread_mutex_destroy(&mutex) == EBUSY)
return RC_NOT_OWNER;
  Back to top
Locking a mutex
  In Win32, the WaitForSingleObject() (see Listing 10) blocks a request for exclusive access to a resourcewithin the current process. A process can block a request in the followingways:

  • If a request for exclusive access to the resource is unlocked, thismethod locks it.
  • If the exclusive access to the resource is already locked, this methodblocks the calling thread until it is unlocked.
  Linux uses a pthread_mutex_lock() (see Listing 11).
  You can also use the pthread_mutex_trylock() to test whether amutex is locked without actually blocking it. If another thread locks themutex, the pthread_mutex_trylock will not block. Itimmediately returns with the error code EBUSY.
Listing 10. Win32 samplecode

if ((rc = WaitForSingleObject(mutex, INFINITE)) == WAIT_FAILED)
return RC_LOCK_ERROR;
Listing 11. Linuxcode

if (rc = pthread_mutex_lock(&mutex))
return RC_LOCK_ERROR;
  Back to top
Releasing or unlocking amutex
  Win32 uses ReleaseMutex() (see Listing12) to release exclusive access to a resource. This call mightfail if the calling thread does not own the mutex object.
  Linux uses pthread_mutex_unlock() to release or unlock themutex (see Listing 13).
Listing 12. Win32 samplecode

If (! ReleaseMutex(mutex))
{
rc = GetLastError();
return RC_UNLOCK_ERROR;
}
Listing 13. Linuxcode

if (rc = pthread_mutex_unlock(&mutex))
return RC_UNLOCK_ERROR;
  Back to top
Mutex sample codes
  Here is the Win32 sample code to acquire a mutex within a process (see Listing 14):
Listing 14. Win32 samplecode

#include
#include
#include

void  thrdproc  (void *data); //the thread procedure (function) to be executed

HANDLE    mutex;

int main( int argc, char **argv )
{
int        hThrd;
unsigned   stacksize;
HANDLE     *threadId1;
HANDLE     *threadId2;
int        arg1;
DWORD  rc;

if( argc < 2 )
arg1 = 7;
else
arg1 = atoi( argv[1] );

printf( "Intra Process Mutex test.\n" );
printf( "Start.\n" );
mutex = CreateMutex(0, FALSE, 0);
if (mutex==NULL)
return RC_OBJECT_NOT_CREATED;

printf( "Mutex created.\n" );

if ((rc = WaitForSingleObject(mutex, INFINITE)) == WAIT_FAILED)
return RC_LOCK_ERROR ;

printf( "Mutex blocked.\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*1000 );

if (! ReleaseMutex(mutex))
{
rc = GetLastError();
return RC_UNLOCK_ERROR;
}

printf( "Mutex released.\n" );
printf( "Main thread sleeps %d sec.\n", arg1 );

Sleep( arg1 * 1000 );

if( WaitForSingleObject(mutex, (DWORD)0) == WAIT_TIMEOUT )
return RC_NOT_OWNER;

CloseHandle(mutex);

printf( "Mutex deleted. (%lx)\n", rc );
printf( "Main thread sleeps 5 sec.\n" );

Sleep( 5*1000 );
printf( "Stop.\n" );
return 0;
}

void thread_proc( void *pParam )
{
DWORDrc;

printf( "\t%s created.\n", pParam );
if ((rc = WaitForSingleObject(mutex, INFINITE)) == WAIT_FAILED)
return RC_LOCK_ERROR;

printf( "\tMutex blocked by %s. (%lx)\n", pParam, rc );
printf( "\t%s sleeps for 5 sec.\n", pParam );

Sleep( 5* 1000 );

if (! ReleaseMutex(mutex))
{
rc = GetLastError();
return RC_UNLOCK_ERROR;
}
printf( "\tMutex released by %s. (%lx)\n", pParam, rc );
}
  An equivalent Linux sample code to acquire mutex within a process (see Listing 15):
Listing 15. EquivalentLinux samplecode

#include
#include
#include
#include
#include

void  thread_proc (void * data);

pthread_mutexattr_t     attr;
pthread_mutex_t   mutex;

int main( int argc, char **argv )
{
pthread_attr_t               pthread_attr;
pthread_attr_t               pthread_attr2;
pthread_t            threadId1;
pthread_t                    threadId2;
int                    arg1;
int             rc = 0;

if( argc < 2 )
arg1 = 7;
else
arg1 = atoi( argv[1] );

printf( "Intra Process Mutex test.\n" );
printf( "Start.\n" );
pthread_mutexattr_init( &attr );
if ( rc = pthread_mutex_init( &mutex, NULL))
{
printf( "Mutex NOT created.\n" );
return RC_OBJECT_NOT_CREATED;
}
printf( "Mutex created.\n" );
if (rc = pthread_mutex_lock (&mutex))
{
printf( "Mutex LOCK ERROR.\n" );
return RC_LOCK_ERROR;
}
printf( "Mutex blocked.\n" );

if (rc = pthread_attr_init(&pthread_attr))
{
printf( "pthread_attr_init ERROR.\n" );
return RC_THREAD_ATTR_ERROR;
}

if (rc = pthread_attr_setstacksize(&pthread_attr, 120*1024))
{
printf( "pthread_attr_setstacksize ERROR.\n" );
return RC_STACKSIZE_ERROR;
}

if (rc = pthread_create(&threadId1,
&pthread_attr,
(void*(*)(void*))thread_proc,
"Thread 1" ))
{
printf( "pthread_create ERROR.\n" );
return RC_THREAD_NOT_CREATED;
}

if (rc = pthread_attr_init(&pthread_attr2))
{
printf( "pthread_attr_init2 ERROR.\n" );
return RC_THREAD_ATTR_ERROR;
}

if (rc = pthread_attr_setstacksize(&pthread_attr2, 120*1024))
{
printf( "pthread_attr_setstacksize2 ERROR.\n" );
return RC_STACKSIZE_ERROR;
}

if (rc = pthread_create(&threadId2,
&pthread_attr2,
(void*(*)(void*))thread_proc,
"Thread 2" ))
{
printf( "pthread_CREATE ERROR2.\n" );
return RC_THREAD_NOT_CREATED;  
}

printf( "Main thread sleeps 5 sec.\n" );
sleep (5);

if (rc = pthread_mutex_unlock(&mutex))
{
printf( "pthread_mutex_unlock ERROR.\n" );
return RC_UNLOCK_ERROR;
}

printf( "Mutex released.\n" );
printf( "Main thread sleeps %d sec.\n", arg1 );
sleep(arg1);

pthread_mutex_destroy(&mutex);

printf( "Main thread sleeps 5 sec.\n" );
sleep( 5 );
printf( "Stop.\n" );
return 0;
}

void thread_proc( void *pParam )
{
intnRet;

printf( "\t%s created.\n", pParam );
if (nRet = pthread_mutex_lock(&mutex))
{
printf( "thread_proc Mutex LOCK ERROR.\n" );
return RC_LOCK_ERROR;
}
printf( "\tMutex blocked by %s. (%lx)\n", pParam, nRet );
printf( "\t%s sleeps for 5 sec.\n", pParam );
sleep(5);
if (nRet = pthread_mutex_unlock(&mutex))
{
printf( " thread_proc :pthread_mutex_unlock ERROR.\n" );
return RC_UNLOCK_ERROR;
}

printf( "\tMutex released by %s. (%lx)\n", pParam, nRet );
}
  Here is another Win32 sample code to acquire mutex between processes.
  Mutexes are system-wide objects which multiple processes can see. IfProgram A creates a mutex, Program B can see that same mutex. Mutexes havenames, and only one mutex of a given name can exist on a machine at atime. If you create a mutex called "My Mutex", no other program can createa mutex with that name, as shown in Listings 16 and 18 below.
Listing 16. Win32 interprocess mutex sample code Process1

#include
#include

#define WAIT_FOR_ENTER  printf( "Press ENTER\n" );getchar()

int main()
{
HANDLEmutex;
DWORD   rc;

printf( "Inter Process Mutex test - Process 1.\n" );
printf( "Start.\n" );

SECURITY_ATTRIBUTES    sec_attr;

sec_attr.nLength              = sizeof( SECURITY_ATTRIBUTES );
sec_attr.lpSecurityDescriptor = NULL;
sec_attr.bInheritHandle       = TRUE;

mutex = CreateMutex(&sec_attr, FALSE, "My Mutex");
if( mutex == (HANDLE) NULL )
return RC_OBJECT_NOT_CREATED;

printf( "Mutex created.\n" );

WAIT_FOR_ENTER;

if ( WaitForSingleObject(mutex, INFINITE) == WAIT_FAILED)
return RC_LOCK_ERROR;

printf( "Mutex blocked.\n" );
WAIT_FOR_ENTER;

if( ! ReleaseMutex(mutex) )
{
rc = GetLastError();
return RC_UNLOCK_ERROR;
}

printf( "Mutex released.\n" );

WAIT_FOR_ENTER;

CloseHandle (mutex);

printf( "Mutex deleted.\n" );
printf( "Stop.\n" );

return OK;
}
  In here, the System V Interprocess Communications (IPC) functions are usedfor Linux implementation, as shown in Listings 17 and 19.
Listing 17. EquivalentLinux sample code Process1

#include
#include
#include
#include

#define WAIT_FOR_ENTER    printf( "Press ENTER\n" );getchar()

union semun {
int                 val;   /* value for SETVAL             */
struct semid_ds    *buf;   /* buffer for IPC_STAT, IPC_SET */
unsigned short     *array; /* array for GETALL, SETALL     */
struct seminfo     __buf;  /* buffer for IPC info          */
};

main()
{
int       shr_sem;
key_t        semKey;
struct sembuf   semBuf;
intflag;
union semun      arg;

printf( "Inter Process Mutex test - Process 1.\n" );
printf( "Start.\n" );

flag = IPC_CREAT;

if( ( semKey = (key_t) atol( "My Mutex" ) ) == 0 )
return RC_INVALID_PARAM;

flag |= S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;

shr_sem  = (int) semget( semKey, 1, flag );

if (shr_sem < 0)
return RC_OBJECT_NOT_CREATED;

arg.val = 1;
if (semctl(shr_sem, 0, SETVAL, arg) == -1)
return RC_OBJECT_NOT_CREATED;

printf( "Mutex created.\n" );

WAIT_FOR_ENTER;

semBuf.sem_num = 0;
semBuf.sem_op = -1;
semBuf.sem_flg = SEM_UNDO;
if (semop(shr_sem, &semBuf, 1) != 0)
return RC_LOCK_ERROR;

printf( "Mutex blocked.\n" );

WAIT_FOR_ENTER;

semBuf.sem_num = 0;
semBuf.sem_op  = 1;
semBuf.sem_flg = SEM_UNDO;

if (semop(shr_sem, &semBuf, 1) != 0)
return RC_UNLOCK_ERROR;

printf( "Mutex released.\n" );

WAIT_FOR_ENTER;

semctl( shr_sem, 0, IPC_RMID );

printf( "Mutex deleted.\n" );
printf( "Stop.\n" );

return 0;
Listing 18. Win32 interprocess mutex sample code Process2

#include
#include


int main()
{
HANDLE      mutex;

printf( "Inter Process Mutex 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;

mutex = OpenMutex(MUTEX_ALL_ACCESS, TRUE, ?“My Mutex");
if( mutex == (HANDLE) NULL )
return RC_OBJECT_NOT_CREATED;

printf( "Mutex opened. \n");
printf( "Try to block mutex.\n" );

if ( WaitForSingleObject(mutex, INFINITE) == WAIT_FAILED)
return RC_LOCK_ERROR;

printf( "Mutex blocked. \n" );
printf( "Try to release mutex.\n" );

if( ! ReleaseMutex(mutex) )
return RC_UNLOCK_ERROR;

printf( "Mutex released.\n" );

CloseHandle (mutex);

printf( "Mutex closed. \n");
printf( "Stop.\n" );

return OK;
}
Listing 19. EquivalentLinux sample code Process2

#include
#include
#include
#include
#include

int main()
{
int             mutex;
key_t           semKey;
struct sembuf   semBuf;
int             flag;
int       nRet=0;

printf( "Inter Process Mutex test - Process 2.\n" );
printf( "Start.\n" );

flag = 0;

if( ( semKey = (key_t) atol( "My Mutex" ) ) == 0 )
return RC_INVALID_PARAM;

flag |= S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;

mutex = (int) semget( semKey, 1, flag );

if (mutex == -1)
return RC_OBJECT_NOT_CREATED;

printf( "Mutex opened \n");
printf( "Try to block mutex.\n" );

semBuf.sem_num = 0;
semBuf.sem_op = -1;
semBuf.sem_flg = SEM_UNDO;
if (semop(mutex, &semBuf, 1) != 0)
return RC_LOCK_ERROR;

printf( "Mutex blocked. \n");
printf( "Try to release mutex.\n" );

semBuf.sem_num = 0;
semBuf.sem_op  = 1;
semBuf.sem_flg = SEM_UNDO;
if (semop(mutex, &semBuf, 1) != 0)
return RC_UNLOCK_ERROR;

printf( "Mutex released. \n");

printf( "Mutex closed. \n");
printf( "Stop.\n" );

return 0;
}
  Back to top
Conclusion
  In this article, we covered the mapping of Win32 to Linux with respect tomutex APIs. We also referenced lists of mutex sample codes to help youwhen you undertake the migration activity involving Win32 to Linux. Thenext article in this series will cover semaphores.
Notice updates
  IBM Corporation 1994-2005. All rights reserved.
  References in this document to IBM products or services do not imply thatIBM intends to make them available in every country.
  IBM, eServer, and pSeries are registered trademarks or trademarks of theIBM Corporation in the United States or other countries or both.
  Microsoft, Windows, Windows NT, and the Windows logo are trademarks ofMicrosoft Corporation in the United States, other countries, or both.
  Intel, Intel Inside (logos), MMX, and Pentium are trademarks of IntelCorporation in the United States, other countries, or both.
  UNIX is a registered trademark of The Open Group in the United States andother countries.
  Linux is a trademark of Linus Torvalds in the United States, othercountries, or both.
  Other company, product or service names may be trademarks or service marksof others.
  Information is provided "AS IS" without warranty of any kind.
  All customer examples described are presented as illustrations of how thosecustomers have used IBM products and the results they may have achieved.Actual environmental costs and performance characteristics may vary bycustomer.
  Information concerning non-IBM products was obtained from a supplier ofthese products, published announcement material, or other publiclyavailable sources and does not constitute an endorsement of such productsby IBM. Sources for non-IBM list prices and performance numbers are takenfrom publicly available information, including vendor announcements andvendor worldwide homepages. IBM has not tested these products and cannotconfirm the accuracy of performance, capability, or any other claimsrelated to non-IBM products. Questions on the capability of non-IBMproducts should be addressed to the supplier of those products.
  All statements regarding IBM future direction and intent are subject tochange or withdrawal without notice, and represent goals and objectivesonly. Contact your local IBM office or IBM authorized reseller for thefull text of the specific Statement of Direction.
  Some information addresses anticipated future capabilities. Suchinformation is not intended as a definitive statement of a commitment tospecific levels of performance, function or delivery schedules withrespect to any future products. Such commitments are only made in IBMproduct announcements. The information is presented here to communicateIBM's current investment and development activities as a good faith effortto help with our customers' future planning.
  Performance is based on measurements and projections using standard IBMbenchmarks in a controlled environment. The actual throughput orperformance that any user will experience will vary depending uponconsiderations such as the amount of multiprogramming in the user's jobstream, the I/O configuration, the storage configuration, and the workloadprocessed. Therefore, no assurance can be given that an individual userwill achieve throughput or performance improvements equivalent to theratios stated here.

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.iyunv.com/thread-149001-1-1.html 上篇帖子: Migrating Win32 C/C++ applications to Linux on POWER, Part 1: Process, thread 下篇帖子: Migrate Win32 C/C++ applications to Linux on POWER, Part 3: Semaphores
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表