互斥量

互斥量(Mutex)是“mutual exclusion”的缩写。互斥量是实现线程同步,和保护同时写共享数据的主要方法。
使用互斥量的典型顺序如下:
1. 创建和初始一个互斥量
2. 多个线程尝试去锁定该互斥量
3. 仅有一个线程可以成功锁定改互斥量
4. 锁定成功的线程做一些处理
5. 线程解锁该互斥量
6. 另外一个线程获得互斥量,重复上述过程
7. 最后销毁互斥量

创建和销毁互斥量

pthread_mutex_t_numtex = PTHREAD_MUTEX_INITIALIZER;
int pthread_mutex_init(pthread_mutex_t *mutex, pthread_mutexattr_t *attr);
int pthread_mutex_destory(pthread_mutex_t *mutex);

互斥量必须用类型pthread_mutex_t类型声明,在使用前必须初始化,这里有两种方法可以初始化互斥量:

  1. 声明时静态地,如:pthread_mutex_t mymutex = PTHREAD_MUTEX_INITIALIZER;
  2. 动态地用pthread_mutex_init()函数,这种方法允许设定互斥量的属性对象attr。

互斥量初始化后是解锁的。

attr对象用于设置互斥量对象的属性,使用时必须声明为pthread_mutextattr_t类型,默认值可以是NULL。

Pthreads标准定义了三种可选的互斥量属性:

  1. 协议(Protocol): 指定了协议用于阻止互斥量的优先级改变
  2. 优先级上限(Prioceiling):指定互斥量的优先级上限
  3. 进程共享(Process-shared):指定进程共享互斥量

注意所有实现都提供了这三个可先的互斥量属性。

pthread_mutexattr_init()和pthread_mutexattr_destroy()函数分别用于创建和销毁互斥量属性对象。

pthread_mutex_destroy()应该用于释放不需要再使用的互斥量对象。

将互斥量和它要保护的数据明显的关联起来是个不错的选择。如下例:

 #include<pthread.h>
#include "errors.h" typedef struct my_struct_tag {
pthread_mutex_t mutex;
int value;
} my_struct_t; int main(int argc, char* argv[])
{
my_struct_t *data;
int status; data = malloc(sizeof(my_struct_t));
if( data == NULL )
errno_abort("malloc");
status = pthread_mutex_init(&data->mutex, NULL);
if( status != )
err_abort(status, "init mutex");
status = pthread_mutex_destroy(&data->mutex);
if( status != )
err_abort(status, "destroy mutex");
(void)free(data);
return status; }

mutex_dynamic.c

加锁和解锁互斥量

int pthread_mutex_lock(pthread_mutex_t *mutex);
int phtread_mutex_trylock(pthread_mutex_t *mutex); //非阻塞加锁
int pthrad_mutex_unlock(pthread_mutex_t *mutex);

线程用pthread_mutex_lock()函数去锁定指定的mutex变量,若该mutex已经被另外一个线程锁定了,该调用将会阻塞线程直到mutex被解锁。

pthread_mutex_trylock()尝试着去锁定一个互斥量,然而,若互斥量已被锁定,程序会立刻返回并返回一个忙错误(EBUSY)值。该函数在优先级改变情况下阻止死锁是非常有用的。

线程可以用pthread_mutex_unlock()解锁自己占用的互斥量。在一个线程完成对保护数据的使用,而其它线程要获得互斥量在保护数据上工作时,可以调用该函数。

若有一下情形则会发生错误:

  1. 互斥量已经被解锁
  2. 互斥量被另一个线程占用
 #include<pthread.h>
#include<time.h>
#include "errors.h" typedef struct alarm_tag {
struct alarm_tag *link;
int seconds;
time_t time;
char message[];
} alarm_t; pthread_mutex_t alarm_mutex = PTHREAD_MUTEX_INITIALIZER;
alarm_t *alarm_list = NULL; void *alarm_thread(void *arg)
{
alarm_t *alarm;
int sleep_time;
time_t now;
int status; while()
{
status = pthread_mutex_lock(&alarm_mutex);
if( status != )
err_abort(status, "Lock mutex");
alarm = alarm_list;
if( alarm == NULL )
sleep_time = ;
else{
alarm_list = alarm->link;
now = time(NULL);
if( alarm->time <= now)
sleep_time = ;
else
sleep_time = alarm->time - now;
#ifdef DEBUG
printf("[waiting: %d(%d)\"%s\"]\n", alarm->time,
sleep_time, alarm->message);
#endif
}
status = pthread_mutex_unlock(&alarm_mutex);
if(status != )
err_abort(status, "Unlock mutex");
if( sleep_time > )
sleep(sleep_time);
else
sched_yield();
if( alarm != NULL)
{
printf("(%d) %s\n", alarm->seconds, alarm->message);
free(alarm);
} }
} int main(int argc, char *argv[])
{
int status;
char line[];
alarm_t *alarm, **current, *next;
pthread_t thread; status = pthread_create(&thread, NULL, alarm_thread, NULL);
if(status != )
err_abort(status, "Create alarm thread");
while()
{
printf("Alarm> ");
if(fgets(line, sizeof(line), stdin) == NULL ) exit();
if(strlen(line) <= ) continue;
alarm = (alarm_t*)malloc(sizeof(alarm_t));
if(alarm == NULL)
errno_abort("malloc alarm"); if(sscanf(line, "%d %64[^\n]", &alarm->seconds, alarm->message) < )
{
fprintf(stderr, "Bad command\n");
free(alarm);
}
else
{
status = pthread_mutex_lock(&alarm_mutex);
if(status != )
err_abort(status, "mutex lock");
alarm->time = time(NULL) + alarm->seconds; current = &alarm_list;
next = *current;
while(next != NULL)
{
if(next->time >= alarm->time)
{
alarm->link = next;
*current = alarm;
break;
}
current = &next->link;
next = next->link;
}
if(next == NULL)
{
*current = alarm;
alarm->link = NULL;
}
#ifdef DEBUG
printf("[list:");
for(next = alarm_list;next != NULL; next = next->link)
printf("%d(%d)[\"%s\"] ", next->time,
next->time - time(NULL), next->message);
printf("]\n");
#endif
status = pthread_mutex_unlock(&alarm_mutex);
if(status != )
err_abort(status, "Unlock mutex");
}
}
}

alarm_mutex.c

在试锁和回退算法中,总是应该以相反的顺序解锁互斥量:

  • 尝试加锁互斥量1;如果成功,再加锁互斥量2;如果成功,再加锁互斥量3。如果某一个互斥量加锁失败,则全部回退。
  • 解锁互斥量3/2/1

按照相反顺序解锁,如果第二个线程需要加锁这三个互斥量,则会由于加锁互斥量1失败而回退;而如果先解锁1-2-3这样的顺序,可能会到加锁互斥量3时候才失败,回退代价更大。

 #include<pthread.h>
#include "errors.h" #define ITERATIONS 10 pthread_mutex_t mutex[] = {
PTHREAD_MUTEX_INITIALIZER,
PTHREAD_MUTEX_INITIALIZER,
PTHREAD_MUTEX_INITIALIZER
}; int backoff = ;
int yield_flag = ; void * lock_forward(void* arg)
{
int i, iterate, backoffs, status;
for( iterate = ; iterate < ITERATIONS; iterate++ ){
backoffs = ;
for( i=; i< ; i++ ){
if( i == ){
status = pthread_mutex_lock(&mutex[i]);
if(status != )
err_abort(status, "First lock");
}else{
if(backoff)
status = pthread_mutex_trylock(&mutex[i]);
else
status = pthread_mutex_lock(&mutex[i]);
if( status == EBUSY) {
backoffs++;
DPRINTF((
" [forward locker"
"backing off at %d]\n",
i));
for(; i>= ;i--) {
status = pthread_mutex_unlock(&mutex[i]);
if(status != )
err_abort(status, "Backoff");
}
}else {
if( status != )
err_abort(status, "Lock mutex");
DPRINTF((" forward locker got %d \n", i));
}
}
if(yield_flag){
if(yield_flag > )
sched_yield();
else
sleep();
}
}
printf("lock forward got all locks, %d backoffs\n", backoffs);
pthread_mutex_unlock(&mutex[]);
pthread_mutex_unlock(&mutex[]);
pthread_mutex_unlock(&mutex[]);
sched_yield();
}
return NULL;
} void *lock_backward(void *arg)
{
int i, iterate, backoffs;
int status; for ( iterate = ; iterate < ITERATIONS; iterate++ ) {
backoffs = ;
for ( i = ; i >= ; i-- ) {
if (i == ) {
status = pthread_mutex_lock (&mutex[i]);
if (status != )
err_abort(status, "First lock");
} else {
if (backoff)
status = pthread_mutex_trylock(&mutex[i]);
else
status = pthread_mutex_lock(&mutex[i]);
if (status == EBUSY ) {
backoffs++;
DPRINTF(("[backward locker backing off at %d]\n",i));
for (; i < ; i++) {
status = pthread_mutex_unlock(&mutex[i]);
if (status != )
err_abort(status, "Backoff");
}
} else {
if (status != )
err_abort(status, "Lock mutex");
DPRINTF(("backward locker got %d\n", i));
}
}
if (yield_flag) {
if (yield_flag > )
sched_yield();
else
sleep();
}
}
printf("Lock backward got all locks, %d backoffs\n", backoffs);
pthread_mutex_unlock(&mutex[]);
pthread_mutex_unlock(&mutex[]);
pthread_mutex_unlock(&mutex[]);
sched_yield();
}
return NULL;
} int main(int argc, char* argv[])
{
pthread_t forward, backward;
int status; if (argc > )
backoff = atoi(argv[]);
if (argc > )
yield_flag = atoi(argv[]);
status = pthread_create(&forward, NULL, lock_forward, NULL);
if (status != )
err_abort(status, "Create forward");
status = pthread_create(&backward, NULL, lock_backward, NULL);
if (status != )
err_abort(status, "Create backward");
pthread_exit(NULL); }

backoff.c

  

posix thread互斥量的更多相关文章

  1. 并发编程(一): POSIX 使用互斥量和条件变量实现生产者/消费者问题

    boost的mutex,condition_variable非常好用.但是在Linux上,boost实际上做的是对pthread_mutex_t和pthread_cond_t的一系列的封装.因此通过对 ...

  2. POSIX 使用互斥量和条件变量实现生产者/消费者问题

    boost的mutex,condition_variable非常好用.但是在Linux上,boost实际上做的是对pthread_mutex_t 和pthread_cond_t的一系列的封装.因此通过 ...

  3. 并发编程入门(一): POSIX 使用互斥量和条件变量实现生产者/消费者问题

    boost的mutex,condition_variable非常好用.但是在Linux上,boost实际上做的是对pthread_mutex_t和pthread_cond_t的一系列的封装.因此通过对 ...

  4. posix多线程--互斥量

    多线程程序在线程间共享数据时,如果多个线程同时访问共享数据就可能有问题.互斥量是解决多个线程间共享数据的方法之一. 1.互斥量初始化两种方式:(1)静态初始化 #include <pthread ...

  5. 并发编程(二):分析Boost对 互斥量和条件变量的封装及实现生产者消费者问题

    请阅读上篇文章<并发编程实战: POSIX 使用互斥量和条件变量实现生产者/消费者问题>.当然不阅读亦不影响本篇文章的阅读. Boost的互斥量,条件变量做了很好的封装,因此比" ...

  6. 并发编程入门(二):分析Boost对 互斥量和条件变量的封装及实现生产者消费者问题

    请阅读上篇文章<并发编程实战: POSIX 使用互斥量和条件变量实现生产者/消费者问题>.当然不阅读亦不影响本篇文章的阅读. Boost的互斥量,条件变量做了很好的封装,因此比" ...

  7. Linux多线程实践(5) --Posix信号量与互斥量解决生产者消费者问题

    Posix信号量 Posix 信号量 有名信号量 无名信号量 sem_open sem_init sem_close sem_destroy sem_unlink sem_wait sem_post ...

  8. 生产者-消费者问题:介绍POSIX线程的互斥量和条件变量的使用

    全局初始化互斥量和条件变量(不全局也行,但至少要对线程启动函数可见,这样才能使用.) static pthread_cont_t cond = PTHREAD_COND_INITIALIZER; st ...

  9. posix thread 浅谈

    用Posix thread进行多线程设计,就不怕跨平台了,因为很多OS都兼容Posix thread,如Linux/Windows等,甚至嵌入式系统上(如rt-thread)都支持posix thre ...

随机推荐

  1. Codeforces 633D Fibonacci-ish 暴力

    题意:1000个元素,每个元素的大小-1e9<=a[i]<=1e9,然后让你重新安排这些元素的位置 获得最长的前缀斐波那契数列 分析:枚举第一个元素和第二个元素,因为在题目元素的范围内,最 ...

  2. 嵌入式开发应该掌握的一些Linux命令

    Linux提供了大量的命令,利用它可以有效地完成大量的工作,如磁盘操作.文件存取.目录操作.进程管理.文件权限设定等.所以,在Linux系统上工作离不开使用系统提供的命令.要想真正理解Linux系统, ...

  3. uvalive 4513 Stammering Aliens

    题意:给你一个串,问期中至少出现m次的最长子串及其起始位置的坐标. 思路:hash+LCP+二分答案 #include<cstdio> #include<cstring> #i ...

  4. PHP与MySQL动态网站开发1

    PHP内嵌在HTML中,置于 <?php ?> 标签内 一般php文件扩展名.php 在body结算标签之前 对于远程服务器,可以用ftp工具传程序 打印语句 echo'Hello Wor ...

  5. Android 依赖注入 ButterKnife 基本使用

    ButterKnife 是一个快速 Android View 注入框架,开发者是Jake Wharton,简单的来说,ButterKnife 是用注解的方式替代findViewById和setXXXL ...

  6. Windows下ffmpeg的完美编译

    纠结了好几天,终于搞定了,小结一下. 1.下载ffmpeg源码,官网 2.编译环境Msys的安装配置,http://blog.csdn.net/jszj/article/details/4028716 ...

  7. 射频识别技术漫谈(7)——ID卡【worldsing笔记】

    ID(Identification)是识别的意思,ID卡就是识别卡.ID卡包含范围广泛,只要具有识别功能的卡片都可以叫ID卡,例如条码卡,磁卡都可以是ID卡,我们这儿说的当然是射频识别卡. 射频ID卡 ...

  8. 关于UIImage类的对象两种初始化方法的区别

    1.imageNamed: UIImage *image = [UIImage imageNamed:"]; UIImage的类方法 第一次读取图片的时候,先把这个图片放到缓存中,下次再使用 ...

  9. 使用CSS3和jQuery可伸缩的搜索条

    使用CSS3和jQuery可伸缩的搜索条 helloweba.com 作者:月光光 时间:2013-12-09 21:23 标签: CSS3 jquery 搜索条在我们网站是必不可少的,尤其是在有限的 ...

  10. 【Stage3D学习笔记续】真正的3D世界(四):空间大战雏形

    前面几个星期抽空用Starling做了一个打飞机的小游戏(所以没有接着看书了),准备面试时用的,结果面试还是没过%>_<%...这个游戏打算过几天全部开源了 那么接下来打算这周把<S ...