多任务共享资源需要互斥,VxWorks里可以使用互斥信号量。Posix也定义类似的概念:用于Thread的Mutex
Mutex用于解决Multi-Threading的数据访问冲突,它有两种状态: unlocked (不属于任何线程)、locked (属于某线程,不可能同时属于两个不同的线程)。获得Mutex的线程可以完成"读-改-写"的操作,然后释放给其它线程。其它尝试获得Mutex的线程只能等待。这样"读-改-写"就组成一个原子操作
int pthread_mutex_init(pthread_mutex_t *pMutex, const pthread_mutexattr_t *pAttr);
int pthread_mutex_destroy(pthread_mutex_t *pMutex);
使用pthread_mutex_init(),根据属性pAttr来初始化pMutex。如果pAttr为NULL,则使用默认属性。不同版本的属性定义略有区别
/* Vx6 Kernel */
typedef struct
{
int mutexAttrStatus;
int mutexAttrProtocol;
int mutexAttrPrioceiling;
} pthread_mutexattr_t;
/* Vx6 RTP */
typedef struct
{
int mutexAttrStatus;
int mutexAttrProtocol;
int mutexAttrPrioceiling;
int mutexAttrType;
} pthread_mutexattr_t;
/* Vx7 */
typedef struct
{
int mutexAttrStatus;
int mutexAttrFlags;
int mutexAttrProtocol;
int mutexAttrPrioceiling;
int mutexAttrType;
} pthread_mutexattr_t;
与属性相关的API有这些
/*
* mutexAttrStatus
* PTHREAD_INITIALIZED_OBJ - 默认值
* PTHREAD_DESTROYED_OBJ
*/
int pthread_mutexattr_init(pthread_mutexattr_t *);
int pthread_mutexattr_destroy(pthread_mutexattr_t *);
/*
* mutexAttrType指的是Thread再次lock同一个Mutex时的不同操作
* PTHREAD_MUTEX_NORMAL- 这是默认值,挂起当前Thread(如果是tryLock,则返回EBUSY)
* PTHREAD_MUTEX_ERRORCHECK - 返回EDEADLK(如果是tryLock,则返回EBUSY)
* PTHREAD_MUTEX_RECURSIVE - 成功
*/
int pthread_mutexattr_settype(pthread_mutexattr_t *pAttr, int type);
int pthread_mutexattr_gettype(pthread_mutexattr_t *pAttr, int *pType);
/* mutexAttrFlags
* PTHREAD_PROCESS_PRIVATE - 这是默认值
* PTHREAD_PROCESS_SHARED - 这个Mutex可以在RTP之间共享
*/
int pthread_mutexattr_getpshared(pthread_mutexattr_t *pAttr, int *pPshared);
int pthread_mutexattr_setpshared(pthread_mutexattr_t *pAttr, int shared);
/* mutexAttrFlags
* PTHREAD_MUTEX_STALLED - 这是默认值
* PTHREAD_MUTEX_ROBUST - 已经lock这个Mutex的Thread如果terminated,
* 其它Thread再lock时,就会返回EOWNERDEAD,
* 其它Thread可以调用pthread_mutex_consistent()来修复Muxte,然后调用pthread_mutex_unlock()。
* 如果修复失败,也需要调用pthread_mutex_unlock(),然后再有Thread尝试lock时,就会返回ENOTRECOVERABLE
*/
int pthread_mutexattr_getrobust(pthread_mutexattr_t *pAttr, int *pRobustness);
int pthread_mutexattr_setrobust(pthread_mutexattr_t *pAttr, int robustness);
/*
* mutexAttrProtocol
* PTHREAD_PRIO_NONE - 这是默认值
* PTHREAD_PRIO_INHERIT - 底层的互斥信号量使能SEM_INVERSION_SAFE选项
* PTHREAD_PRIO_PROTECT - 使用这种Protocol之后,lock这个Mutex的Thread会将其优先级提升到mutexAttrPrioceiling。
* unlock时再恢复优先级。
* PTHREAD_PRIO_INHERIT和PTHREAD_PRIO_PROTECT的目的都是解决Priority Inversion的问题。
* PTHREAD_PRIO_INHERIT的效率略高一些,因为它只在必要时改变优先级。
* PTHREAD_PRIO_PROTECT还会阻止优先级高于mutexAttrPrioceiling的Thread。
*/
int pthread_mutexattr_setprotocol(pthread_mutexattr_t *pAttr, int protocol);
int pthread_mutexattr_getprotocol(pthread_mutexattr_t *pAttr, int *pProtocol);
/* mutexAttrPrioceiling,仅在PTHREAD_PRIO_PROTECT时使用 */
int pthread_mutexattr_setprioceiling(pthread_mutexattr_t *pAttr, int prioceiling);
int pthread_mutexattr_getprioceiling(pthread_mutexattr_t *pAttr, int *pPrioceiling);
/* mutexAttr.mutexAttrPrioceiling,仅在PTHREAD_PRIO_PROTECT时使用 */
int pthread_mutex_setprioceiling(pthread_mutex_t *pAttr, int prioceiling, int *pOldPrioceiling);
int pthread_mutex_getprioceiling(pthread_mutex_t *pAttr, int *pPrioceiling);
int pthread_mutex_consistent(pthread_mutex_t *pMutex);
操作Mutex的API有
/*
* 此函数用于lock pMutex
* 如果pMutex处于unlocked状态, 将其置为locked, 并将当前Thread置为其owner.
* 然后pthread_mutex_lock()立即返回.
*
* 如果pMutex已经被其它Thread lock,
* pthread_mutex_lock()阻塞当前Thread,直到Mutex变成unlocked.
*
* 如果Thread再次lock已经被自己lock的Mutex, 那接下来的行为取决于mutexAttrType
*/
int pthread_mutex_lock(pthread_mutex_t *pMutex);
/*
* 如果pMutex已经被其它Thread lock,
* pthread_mutex_lock()阻塞当前Thread,直到Mutex变成unlocked或超时.
* pAbstime是绝对时间
*
* 其它行为与pthread_mutex_lock()一致
*/
int pthread_mutex_timedlock(pthread_mutex_t *pMutex, struct timespec *pAbstime);
/*
* 如果pMutex已经被其它Thread lock, pthread_mutex_trylock()返回EBUSY
*
* 其它行为与pthread_mutex_lock()类似
*/
int pthread_mutex_trylock(pthread_mutex_t *pMutex);
/*
* unlock pMutex
* 如果当前Thread并没有lock这个Mutex,则返回EPERM
* 如果Mutex是PTHREAD_MUTEX_RECURSIVE,且当前Thread已执行过多次lock,则将lock的次数减一
* 否则将Mutex置为unlocked
*/
int pthread_mutex_unlock(pthread_mutex_t *pMutex);
pthread_mutex_lock()的流程图如下,PTHREAD_MUTEX_NORMAL在Linux叫做fast,相应的处理方式是deadlock
pthread_mutex_trylock()的流程图
Vx69里写个RTP的例子
/*
* 版权所有 公众号 VxWorks567
*/
#include <stdio.h> /* printf() */
#include <unistd.h> /* sleep() */
#include <pthread.h> /* pthread_create() */
static pthread_mutex_t mutexid;
static void *thread1(void *arg)
{
int ret;
sleep(1);
/* #define EBUSY 16 Device or resource busy */
printf("Test Mutex: in thread1 0x%x, pthread_mutex_trylock %p begin\n\n", (int)pthread_self(), &mutexid);
ret = pthread_mutex_trylock (&mutexid);
printf("Test Mutex: in thread1 0x%x, pthread_mutex_trylock %p end = %d\n", (int)pthread_self(), &mutexid, ret);
printf("Test Mutex: in thread1 0x%x, pthread_mutex_lock %p begin\n\n", (int)pthread_self(), &mutexid);
ret = pthread_mutex_lock (&mutexid);
printf("Test Mutex: in thread1 0x%x, pthread_mutex_lock %p end = %d\n", (int)pthread_self(), &mutexid, ret);
#if 0
/* #define EDEADLK 35 Resource deadlock would occur */
printf("Test Mutex: in thread1 0x%x, pthread_mutex_lock %p begin\n\n", (int)pthread_self(), &mutexid);
ret = pthread_mutex_lock (&mutexid);
printf("Test Mutex: in thread1 0x%x, pthread_mutex_lock %p end = %d\n", (int)pthread_self(), &mutexid, ret);
printf("Test Mutex: in thread1 0x%x, pthread_mutex_unlock %p begin\n", (int)pthread_self(), &mutexid);
ret = pthread_mutex_unlock (&mutexid);
printf("Test Mutex: in thread1 0x%x, pthread_mutex_unlock %p end = %d\n", (int)pthread_self(), &mutexid, ret);
#endif
/* #define EPERM 1 Operation not permitted */
printf("Test Mutex: in thread1 0x%x, pthread_mutex_unlock %p begin\n", (int)pthread_self(), &mutexid);
ret = pthread_mutex_unlock (&mutexid);
printf("Test Mutex: in thread1 0x%x, pthread_mutex_unlock %p end = %d\n", (int)pthread_self(), &mutexid, ret);
return NULL;
}
static void *thread2(void *arg)
{
int ret;
printf("Test Mutex: in thread2 0x%x, pthread_mutex_lock %p begin\n", (int)pthread_self(), &mutexid);
ret = pthread_mutex_lock (&mutexid);
printf("Test Mutex: in thread2 0x%x, pthread_mutex_lock %p end\n\n", (int)pthread_self(), &mutexid);
sleep(2);
printf("Test Mutex: in thread2 0x%x, pthread_mutex_unlock %p begin\n", (int)pthread_self(), &mutexid);
ret = pthread_mutex_unlock (&mutexid);
printf("Test Mutex: in thread2 0x%x, pthread_mutex_unlock %p end\n", (int)pthread_self(), &mutexid);
return NULL;
}
int main()
{
pthread_t tid1;
pthread_t tid2;
int ret;
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
#if 1
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
#elif 1
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
#else
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
#endif
pthread_mutex_init(&mutexid, &attr);
pthread_mutexattr_destroy(&attr);
printf("Test Mutex: in thread0 0x%x, pthread_mutex_init %p\n", (int)pthread_self(), &mutexid);
ret = pthread_create(&tid1, NULL, &thread1, NULL);
ret = pthread_create(&tid2, NULL, &thread2, NULL);
ret = pthread_join(tid1, NULL);
ret = pthread_join(tid2, NULL);
ret = pthread_mutex_destroy (&mutexid);
printf("Test Mutex: in thread0 0x%x, pthread_mutex_destroy %p\n", (int)pthread_self(), &mutexid);
return 0;
}