ref http://www.ibm.com/developerworks/cn/linux/thread/posix_thread1/index.html

 #include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
int myglobal;
void *thread_function(void *arg) {
int i,j;
for ( i=; i<; i++) {
j=myglobal;
j=j+;
printf(".");
fflush(stdout);
sleep();
myglobal=j;
}
return NULL;
}
int main(void) {
pthread_t mythread;
int i;
if ( pthread_create( &mythread, NULL, thread_function, NULL) ) {
printf("error creating thread.");
abort();
}
for ( i=; i<; i++) {
myglobal=myglobal+;
printf("o");
fflush(stdout);
sleep();
}
if ( pthread_join ( mythread, NULL ) ) {
printf("error joining thread.");
abort();
}
printf("\nmyglobal equals %d\n",myglobal);
exit();
}

打印输出:

$ ./thread2
..o.o.o.o.oo.o.o.o.o.o.o.o.o.o..o.o.o.o.o
myglobal equals

非常意外吧!因为 myglobal 从零开始,主线程和新线程各自对其进行了 20 次加一, 程序结束时 myglobal 值应当等于 40。由于 myglobal 输出结果为 21,这其中肯定有问题。但是究竟是什么呢?

放弃吗?好,让我来解释是怎么一回事。首先查看函数 thread_function()。注意如何将 myglobal 复制到局部变量 "j" 了吗? 接着将 j 加一, 再睡眠一秒,然后到这时才将新的 j 值复制到 myglobal?这就是关键所在。设想一下,如果主线程就在新线程将 myglobal 值复制给 j 立即将 myglobal 加一,会发生什么?当 thread_function() 将 j 的值写回 myglobal 时,就覆盖了主线程所做的修改。

当编写线程程序时,应避免产生这种无用的副作用,否则只会浪费时间(当然,除了编写关于 POSIX 线程的文章时有用)。那么,如何才能排除这种问题呢?

由于是将 myglobal 复制给 j 并且等了一秒之后才写回时产生问题,可以尝试避免使用临时局部变量并直接将 myglobal 加一。虽然这种解决方案对这个特定例子适用,但它还是不正确。如果我们对 myglobal 进行相对复杂的数学运算,而不是简单的加一,这种方法就会失效。但是为什么呢?

要理解这个问题,必须记住线程是并发运行的。即使在单处理器系统上运行(内核利用时间分片模拟多任务)也是可以的,从程序员的角度,想像两个线程是同时执行的。thread2.c 出现问题是因为 thread_function() 依赖以下论据:在 myglobal 加一之前的大约一秒钟期间不会修改 myglobal。需要有些途径让一个线程在对 myglobal 做更改时通知其它线程“不要靠近”。

个人分析:

线程 thread_function 先将global的值保存在j中,然后休眠1秒,在这一秒钟主线程做了global++的操作,然后休眠,当到thread_function 调度执行的时候i仍然保存的是1秒钱的值,然后再加加操作,覆盖了global的值。

所以要加锁

 #include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
int myglobal;
pthread_mutex_t mymutex=PTHREAD_MUTEX_INITIALIZER;
void *thread_function(void *arg) {
int i,j;
for ( i=; i<; i++) {
pthread_mutex_lock(&mymutex);
j=myglobal;
j=j+;
printf(".");
fflush(stdout);
sleep();
myglobal=j;
pthread_mutex_unlock(&mymutex);
}
return NULL;
}
int main(void) {
pthread_t mythread;
int i;
if ( pthread_create( &mythread, NULL, thread_function, NULL) ) {
printf("error creating thread.");
abort();
}
for ( i=; i<; i++) {
pthread_mutex_lock(&mymutex);
myglobal=myglobal+;
pthread_mutex_unlock(&mymutex);
printf("o");
fflush(stdout);
sleep();
}
if ( pthread_join ( mythread, NULL ) ) {
printf("error joining thread.");
abort();
}
printf("\nmyglobal equals %d\n",myglobal);
exit();
}

打印输出:

o....................ooooooooooooooooooo
myglobal equals 40

  

互斥对象是这样工作的。如果线程 a 试图锁定一个互斥对象,而此时线程 b 已锁定了同一个互斥对象时,线程 a 就将进入睡眠状态。一旦线程 b 释放了互斥对象(通过 pthread_mutex_unlock() 调用),线程 a 就能够锁定这个互斥对象(换句话说,线程 a 就将从 pthread_mutex_lock() 函数调用中返回,同时互斥对象被锁定)。同样地,当线程 a 正锁定互斥对象时,如果线程 c 试图锁定互斥对象的话,线程 c 也将临时进入睡眠状态。对已锁定的互斥对象上调用 pthread_mutex_lock() 的所有线程都将进入睡眠状态,这些睡眠的线程将“排队”访问这个互斥对象。

通常使用 pthread_mutex_lock() 和 pthread_mutex_unlock() 来保护数据结构。这就是说,通过线程的锁定和解锁,对于某一数据结构,确保某一时刻只能有一个线程能够访问它。可以推测到,当线程试图锁定一个未加锁的互斥对象时,POSIX 线程库将同意锁定,而不会使线程进入睡眠状态。

所以现在的结果是正确的

许多互斥对象

如果放置了过多的互斥对象,代码就没有什么并发性可言,运行起来也比单线程解决方案慢。如果放置了过少的互斥对象,代码将出现奇怪和令人尴尬的错误。幸运的是,有一个中间立场。首先,互斥对象是用于串行化存取*共享数据*。不要对非共享数据使用互斥对象,并且,如果程序逻辑确保任何时候都只有一个线程能存取特定数据结构,那么也不要使用互斥对象。

其次,如果要使用共享数据,那么在读、写共享数据时都应使用互斥对象。用 pthread_mutex_lock() 和 pthread_mutex_unlock() 把读写部分保护起来,或者在程序中不固定的地方随机使用它们。学会从一个线程的角度来审视代码,并确保程序中每一个线程对内存的观点都是一致和合适的。为了熟悉互斥对象的用法,最初可能要花好几个小时来编写代码,但是很快就会习惯并且*也*不必多想就能够正确使用它们。

pthread 学习系列 case2-- 使用互斥锁的更多相关文章

  1. pthread 学习系列 case2-- pthread_mutex_t

    许多互斥对象 如果放置了过多的互斥对象,代码就没有什么并发性可言,运行起来也比单线程解决方案慢.如果放置了过少的互斥对象,代码将出现奇怪和令人尴尬的错误.幸运的是,有一个中间立场.首先,互斥对象是用于 ...

  2. pthread 学习系列 case1-- 共享进程数据 VS 进程

    #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <pthread.h& ...

  3. 分布式缓存技术redis学习系列(五)——redis实战(redis与spring整合,分布式锁实现)

    本文是redis学习系列的第五篇,点击下面链接可回看系列文章 <redis简介以及linux上的安装> <详细讲解redis数据结构(内存模型)以及常用命令> <redi ...

  4. Java并发包源码学习系列:ReentrantLock可重入独占锁详解

    目录 基本用法介绍 继承体系 构造方法 state状态表示 获取锁 void lock()方法 NonfairSync FairSync 公平与非公平策略的差异 void lockInterrupti ...

  5. Java多线程系列--“JUC锁”02之 互斥锁ReentrantLock

    本章对ReentrantLock包进行基本介绍,这一章主要对ReentrantLock进行概括性的介绍,内容包括:ReentrantLock介绍ReentrantLock函数列表ReentrantLo ...

  6. linux c学习笔记----互斥锁属性

    转自:http://lobert.iteye.com/blog/1762844 互斥锁属性 使用互斥锁(互斥)可以使线程按顺序执行.通常,互斥锁通过确保一次只有一个线程执行代码的临界段来同步多个线程. ...

  7. pthread mutex 进程间互斥锁实例

    共享标志 定义 名称 描述 0 PTHREAD_PROCESS_PRIVATE 进程内互斥锁 仅可当前进程内共享 1 PTHREAD_PROCESS_SHARED 进程间互斥锁 多个进程间共享 第一个 ...

  8. APUE学习笔记——11 线程同步、互斥锁、自旋锁、条件变量

    线程同步     同属于一个进程的不同线程是共享内存的,因而在执行过程中需要考虑数据的一致性.     假设:进程有一变量i=0,线程A执行i++,线程B执行i++,那么最终i的取值是多少呢?似乎一定 ...

  9. 互斥锁和条件变量(pthread)相关函数

    互斥锁 #include <pthread.h> // 若成功返回0,出错返回正的Exxx值 // mptr通常被初始化为PTHREAD_MUTEX_INITIALIZER int pth ...

随机推荐

  1. 【每日学习】Apache重写未开启,导致The requested URL /xxxx.html was not found on this server

    今天把项目环境从集成换成独立的,全部搭建好后,网站主页www.xxx.com能打开,但一涉及到跳转,带参数,比如 www.xxx.com/xxx/xxx.html 就会报错 The requested ...

  2. 34-php基础:cookie

    <?php //1.创建cookie //创建cookie,如下设置,cookie的过期时间为会话结束时 setcookie("name","gaoxiong&qu ...

  3. MSMQ消息队列安装

    一.Windows 7安装.管理消息队列1.安装消息队列   执行用户必须要有本地 Administrators 组中的成员身份,或等效身份.   具体步骤:    开始—>控制面板—>程 ...

  4. 手把手教你开发chrome扩展一:开发Chrome Extenstion其实很简单

    手把手教你开发chrome扩展一:开发Chrome Extenstion其实很简单   手把手教你开发chrome扩展一:开发Chrome Extenstion其实很简单 手把手教你开发Chrome扩 ...

  5. word 2010自定义快捷键提高工作效率

    经常使用word处理文档, 做笔记的时候会把word文档框缩小,以便同时看pdf同时记录笔记,但是缩小的word框不能把所有的菜单项显示出来,我比较常用那个插入边框下面的那个横线来做分割符,但是缩小了 ...

  6. IOS开发之—— 上传头像的使用

    static NSString *const uploadSuccess = @"更改头像成功"; @interface DMAccountInformationViewContr ...

  7. 利用link标签的disabed属性大面积的对其他标签元素的CSS样式进行替换操作

    由于平时对元素样式的控制基本上只是3,4个,所以一般用Jquery的时候直接使用$(element).css();这个方法,或者使用$(element).addClass()方法完成样式操作.对于小范 ...

  8. 轻松理解JS基本包装对象

    今天来讨论一下JS中的基本包装对象(也叫基本包装类型),之前刚学到这里的时候,自己也是一头雾水,不明白这个基本包装对象到底是个什么鬼,后来找了很多资料,终于看清了它的真面目.首先呢,我们现在复习一下J ...

  9. 利用php实现文件迁移重命名

    首先表明,这是一个悲伤的故事. 暑假来临,学校安排我们到某软件外包公司实习,想想不用面试也是蛮方便的,可以借此机会向大牛学习学习,虽然没有工资(据说学校还交了600块的保险),但想想还是蛮期待的,但真 ...

  10. zoeDylan.ImgChange 图片切换插件

    墨芈深夜发布插件——图片切换 附上下载地址:http://pan.baidu.com/s/17kKF3共享天地/[墨芈 插件]zoeDylan Plugins Code JS (function ($ ...