将 Win32 C/C 应用程序迁移到 POWER 上的 Linux,第 2 部分: 互斥

来源:百度文库 编辑:神马文学网 时间:2024/03/29 08:39:09

将 Win32 C/C++ 应用程序迁移到 POWER 上的 Linux,第 2 部分: 互斥

文档选项

打印本页

将此页作为电子邮件发送


级别: 初级

Nam Keung (mailto:namkeung@us.ibm.com), 高级程序员, IBM 
Chakarat Skawratananond (mailto:chakarat@us.ibm.com), pSeries Linux 技术顾问, IBM 

2005 年 2 月 10 日
更新 2005 年 4 月 21 日

本系列文章可以帮助您将 Win32 C/C++ 应用程序移植到 POWER 上的 Linux。高级程序员 Nam Keung 和 pSeries® Linux 技术顾问 Chakarat Skawratananond 从互斥(mutex)应用程序接口(application program interface,API)的角度阐述了从 Win32 到 Linux 的映射。本系列的 第 1 部分 集中关注的是 Win32 API 的映射。

介绍

本文关注的是互斥原语(primitives)。建议您在继续阅读之前先回顾本系列 第 1 部分 中的下列章节:

  • 初始化
  • 进程
  • 线程
  • 共享内存




回页首

互斥

如下面的 表 1 所示,互斥提供线程间资源的独占访问控制。 它是一个简单的锁,只有持有它的线程才可以释放那个互斥。它确保了它们正在访问的共享资源的完整性 (最常见的是共享数据),因为在同一时刻只允许一个线程访问它。


表 1. 互斥
Win32 Linux CreateMutex(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)



回页首

创建互斥

在 Win NT/Win2K 中,所有互斥都是递归的。

在 Win32 中,CreateMutex() 为当前进程中的线程提供资料的独占访问控制。 此方法让线程可以串行化对进程内资源的访问。创建了互斥句柄(mutual exclusion handle)后, 当前进程中的所有线程都可以使用它(见下面的 清单 1)。


清单 1. 创建互斥
HANDLE CreateMutex(                    LPSECURITY_ATTRIBUTESlMutexAttributes,                    BOOLlInitialOwner,                    LPCTSTRlName                    )                    

Linux 使用 pthread 库调用 pthread_mutex_init() 来创建互斥,如下面的 清单 2 所示。


清单 2. pthread
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr);

Linux 有三种类型的互斥。互斥类型决定了在 pthread_mutex_lock 中线程尝试锁定一个它已经持有的互斥时 所发生的情形:

Fast mutex:
当尝试使用 pthread_mutex_lock() 去锁定互斥时,进行调用的线程会永远挂起。
Recursive mutex:
pthread_mutex_lock() 立即返回成功返回代码。
Error check mutex:
pthread_mutex_lock() 立即返回错误代码 EDEADLK。

可以以两种方式设置互斥的类型。清单 3 介绍了设置互斥的静态方法。


清单 3. 设置互斥的静态方法
/* For Fast mutexes */                    pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;                    /* For recursive mutexes */                    

您可以使用这个函数来锁定互斥:pthread_mutex_lock(pthread_mutex_t *mutex)。 这个函数会获得一个指向它正在尝试锁定的互斥的指针。当互斥被锁定或者发生错误时,函数返回。 那个错误不是归咎于被锁定的互斥。函数会等待互斥被解锁。

设置互斥的另一种方式是使用互斥属性对象。为此,要调用 pthread_mutexattr_init() 来初始化对象,然后调用 pthread_mutexattr_settype() 来设置互斥的类型,如下面的 清单 4 所示。


清单 4. 通过属性设置互斥
int pthread_mutexattr_init(pthread_mutexattr_t *attr);                    int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int kind);                    

使用下面的函数解开对互斥的锁定(见 清单 5):

这里是创建互斥的示例代码(见下面的 6 和 7)。


清单 5. 解锁函数
pthread_mutex_unlock(pthread_mutex_t *mutex))


清单 6. Win32 示例代码

HANDLE mutex;                    mutex = CreateMutex(0, FALSE, 0);                    if (!(mutex))                    {                    return RC_OBJECT_NOT_CREATED;                    }                    


清单 7. 相应的 Linux 代码

pthread_mutexattr_t  attr;                    pthread_mutex_t      mutex;                    pthread_mutexattr_init (&attr);                    if (rc = pthread_mutex_init(&mutex, &attr))                    {                    return RC_OBJECT_NOT_CREATED;                    }                    





回页首

销毁互斥

在 Win32 中,CloseHandle() 方法(见 清单 8) 可以删除为当前进程中资源提供独占访问控制的对象。删除那个对象后,那个互斥对象就会无效,直到 CloseHandle() 方法通过调用 CreateMutex 重新初始化它。

当不再对资源进行独占访问后,您应该调用这个方法销毁它。如果您需要放弃那个对象的所有权,那么应该调用 ReleaseMutex() 方法。

在 Linux 中,pthread_mutex_destroy() 会销毁互斥对象,这会释放它可能会 持有的资源。它还会检查互斥在那个时刻是不是解除锁定的(见清单 9)。


清单 8. Win32 示例代码
if(WaitForSingleObject(mutex, (DWORD)0) == WAIT_TIMEOUT )                    return RC_NOT_OWNER;                    CloseHandle(mutex);                    


清单 9. Linux 代码

if (pthread_mutex_destroy(&mutex) == EBUSY)                    return RC_NOT_OWNER;                    





回页首

锁定互斥

在 Win32 中,WaitForSingleObject()(见 清单 10) 会阻塞对当前进程内资源的独占访问的请求。进程可以通过下面的方式阻塞请求:

  1. 如果独占访问请求的资源没有被锁定,则这个方法锁定它。
  2. 如果独占访问的资源已经被锁定,则此方法阻塞那个调用线程,直到那个资源被解除锁定。

Linux 使用 pthread_mutex_lock()(见 清单 11)。

您还可以使用 pthread_mutex_trylock() 来测试某个互斥是否已经被锁定,而不需要真正 地去锁定它。如果另一个线程锁定了那个互斥,则 pthread_mutex_trylock 将不会阻塞。 它会立即返回错误代码 EBUSY。


清单 10. Win32 示例代码
if ((rc = WaitForSingleObject(mutex, INFINITE)) == WAIT_FAILED)                    return RC_LOCK_ERROR;                    


清单 11. Linux 代码

if (rc = pthread_mutex_lock(&mutex))                    return RC_LOCK_ERROR;                    





回页首

释放或者解锁互斥

Win32 使用 ReleaseMutex()(见 清单 12) 来释放对资源的独占访问。如果进行调用的线程并不拥有那个互斥对象,则这个调用可能会失败。

Linux 使用 pthread_mutex_unlock() 来释放或者解锁互斥 (见清单 13)。


清单 12. Win32 示例代码
If (! ReleaseMutex(mutex))                    {                    rc = GetLastError();                    return RC_UNLOCK_ERROR;                    }                    


清单 13. Linux 示例代码

if (rc = pthread_mutex_unlock(&mutex))                    return RC_UNLOCK_ERROR;





回页首

Mutex 示例代码

这里是获得进程内互斥的 Win32 示例代码(见 Listing 14):


清单 14. Win32 示例代码
#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 );                    }                    

相应的获得进程内互斥的 Linux 示例代码(见 清单 15):


清单 15. 相应的 Linux 示例代码
#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 );                    }                    

这里是获得进程间互斥的另一 Win32 示例代码。

互斥是系统范围内对象,可以由多个进程使用。如果程序 A 创建一个互斥,则程序 B 可以使用同一个互斥。 互斥有名称,并且,一个给定名称的互斥在同一机器上同一时刻只能存在一个。如果您创建了一个名为“My Mutex” 的互斥,则任何其他程序都不能使用这个名称创建互斥,如下面的清单 16 和 18 所示。


清单 16. Win32 进程间互斥示例代码 Process 1
#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;                    }                    

在此,Linux 实现使用的是 System V Interprocess Communications(IPC)函数,如清单 17 和 19 所示。


清单 17. 相应的 Linux 示例代码 Process 1
#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;                    


清单 18. Win32 进程间示例代码 Process 2

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


清单 19. 相应的 Linux 示例代码 Process 2

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





回页首

结束语

在本文中,我们介绍了互斥 API 从 Win32 到 Linux 的映射。我们还引用了一系列互斥示例代码来帮助您进行 从 Win32 到 Linux 的迁移行动。本系列的下一篇文章将阐述信号量。

补充声明

IBM Corporation 1994-2005。保留所有权利。

本文档中对 IBM 产品或服务的引用并不表示 IBM 想要让它们在所有国家都可用。

IBM、eServer 和 pSeries 是 IBM Corporation 在美国和/或其他国家或地区的商标。

Microsoft、Windows、Windows NT 和 Windows 徽标是 Microsoft Corporation 在美国和/或其他国家或地区的商标或注册商标。

Intel、Intel Inside(logos)、MMX 和 Pentium 是 Intel 公司在美国和/或其他国家或地区的商标。

UNIX 是 The Open Group 在美国和其他国家或地区的注册商标。

Linux 是 Linus Torvalds 在美国和/或其他国家或地区的商标。

其他公司、产品或服务名称可能是其他公司的商标或服务标记。

信息都是“按原样”发布,没有任何类型的保证。

所描述的所有的客户示例只是为了说明那些客户如何使用 IBM 产品,以及它们可能获得的结果。 不同客户所得到的实际环境代价和性能特性可能会不同。

涉及非 IBM 产品的信息可从这些产品的供应商、其出版说明或其他可公开获得的资料中获取, 并不构成 IBM 对此产品的认可。非 IBM 价目及性能数字资源取自可公开获得的信息, 包括供应商的声明和供应商的全球主页。 IBM 没有对这些产品进行测试,也无法确认其性能的精确性、 兼容性或任何其他关于非 IBM 产品的声明。有关非 IBM 产品性能的问题应当向这些产品的供应商提出。

所有关于 IBM 未来方向或意向的声明都可随时更改或收回,而不另行通知, 它们仅仅表示了目标和意愿而已。联系您本地的 IBM 办公人员或者 IBM 授权的转销商, 以获得特定的 Statement of General Direction 的全文。

这里所包含的信息可能陈述了预期的未来功能。上述信息并不打算作为对任何未来产品的特定性能级别、 功能或交付时间表的明确承诺。这样的承诺只会在 IBM 产品中作出。这里出现的信息用于表明 IBM 当前的投资和发展活动,作为一种信任,来帮助我们的客户规划未来。

性能是在受控环境中使用标准的 IBM 基准程序测试和估算的。任何用户实际的吞吐量或性能可能各不相同, 这取决于需要考虑的事项,例如用户作业流中的多道程序设计总量、I/O 配置、存储器配置和处理的工作负载。 因此,我们不能担保,个别用户所获得的吞吐量或性能改善等同于这里所列的值。



参考资料

  • 您可以参阅本文在 developerWorks 全球站点上的 英文原文。

  • 阅读 将 Win32 C/C++ 应用程序迁移到 POWER 上的 Linux 系列中的其他部分:
    • 进程、线程和共享内存服务

  • 访问 Virtual Innovation Center for Hardware 以获得 AIX® 开发支持。这是所有 pSeries AIX 开发的最主要参考资料。

  • 访问 Developer Bookstore 以获得详尽的技术书籍列表, 包括数百本 与 eServer 相关的书籍。

  • 还想要更多?developerWorks eServer 专区 有许许多多报道性文章以及初级的、中级的和高级的 eServer 教程。

  • 在 Linux on POWER 了解:ISV 和开发者如何评论 Linux on POWER、事件、Linux on iSeries、 Linux on pSeries、Linux on BladeCenter,等等。

  • 通过参与 developerWorks blogs 加入 developerWorks 社区。

  • IBM® developerWorks 团队在全世界举办了许多 technical briefings, 您可以免费参加。


作者简介

 

Nam Keung 是 IBM 的一名高级程序员,他曾致力于 AIX 通信开发、AIX 多媒体、SOM/DSOM 开发和 Java 性能方面的工作。他目前的工作包括帮助独立软件提供商(Independent Software Vendors,ISV) 进行应用程序设计、部署应用程序、性能调优和关于 pSeries 平台的教育。 您可以通过 namkeung@us.ibm.com 与 Nam 联系。


 

Chakarat Skawratananond 是 IBM eServer Solutions Enablement 组织的一名技术顾问, 在那里,他帮助独立软件开发商在 IBM pSeries 平台上使用他们的用于 AIX 和 Linux 的应用程序。 您可以通过 chakarat@us.ibm.com 与 Chakarat 联系。