下面我们来看看这个demo

#include <stdio.h>

#include <pthread.h>

#include <unistd.h>

#include <stdlib.h>

int myglobal;

void * thread_function(void * arg)

{

int i,j;

for (i=0; i<20; i++) {

j=myglobal;

j++;

printf(".");

fflush(stdout);

sleep(1);

myglobal=j;

}

return  NULL;

}

int main(int argc, const char * argv[])

{

pthread_t mythread;

int i;

if (pthread_create(&mythread, NULL, thread_function, NULL)) {

printf("error creating thread");

abort();

}

for (i=0; i<20; i++) {

myglobal++;

printf("o");

fflush(stdout);

sleep(1);

}

if (pthread_join(mythread, NULL)) {

printf("error joining thread");

abort();

}

printf("\nmyglobal equals %d\n",myglobal);

return 0;

}

对于这个问题,我们知道是这个全局变量没有保护的问题,这样导致一个线程的更改覆盖了另外一个线程的改变。
那下面我们就对这个全局变量myglobal加锁。即在myglobal的范围上下加上lock和unlock,具体如下:

#include <stdio.h>

#include <pthread.h>

#include <unistd.h>

#include <stdlib.h>

int myglobal;

pthread_mutex_t mymutex=PTHREAD_MUTEX_INITIALIZER;

void * thread_function(void * arg)

{

int i,j;

for (i=0; i<20; i++) {

pthread_mutex_lock(&mymutex);

j=myglobal;

j++;

printf(".");

fflush(stdout);

sleep(1);

myglobal=j;

pthread_mutex_unlock(&mymutex);

}

return  NULL;

}

int main(int argc, const char * argv[])

{

pthread_t mythread;

int i;

if (pthread_create(&mythread, NULL, thread_function, NULL)) {

printf("error creating thread");

abort();

}

for (i=0; i<20; i++) {

pthread_mutex_lock(&mymutex);

myglobal++;

pthread_mutex_unlock(&mymutex);

printf("o");

fflush(stdout);

sleep(1);

}

if (pthread_join(mythread, NULL)) {

printf("error joining thread");

abort();

}

printf("\nmyglobal equals %d\n",myglobal);

return 0;

}

对于线程的运行我们一定不要假设哪个会在前面运行哪个会在后面运行,只要线程创建以后我们可以认为他们是同时运行的。

我们看下互斥对象的使用。

首先是初始化

静态初始化给变量赋一个常数

pthread_mutex_t mymutex=PTHREAD_MUTEX_INITIALIZER;

另外也可以动态的创建互斥对象,即像使用malloc一样动态分配,在这边我们使用

int pthread_mutex_init(pthread_mutex_t *restrict, const pthread_mutexattr_t *restrict)

第一个参数是要初始化的互斥对象,这个指针已经分配好了一块内存,第二个参数是设定互斥量属性的,为空则为默认属性。

如果使用了pthread_mutex_init初始化了互斥对象,就要用pthread_mutex_destory来销毁,其参数为指向要销毁的互斥量。注意的是这边不会释放用来存储互斥量pthread_mutex_t的内存,也就是我们可以直接再用pthread_mutex_init来重新初始化被销毁的内存。

另外我们要注意的是不管是创建还是销毁,成功的时候返回的都是0.

使用

pthread_mutex_lock接受一个互斥对象的指针作为参数,将其锁定,如果该互斥对象已经锁定,则该调用者进入睡眠状态,如果函数返回,则唤醒当前线程。

pthread_mutex_unlock与上述配合使用,看到名字我们知道这个是解锁。

这里我们要明确的是一定要尽快对已经加锁的互斥对象进行解锁,以提高性能。

另外一定不要对没有加锁的互斥对象进行解锁,这样pthread_mutex_unlock会调用失败。

我们会考虑下一个问题就是,计算机要不停的监测这个互斥量的状态,改变状态之后要立即做出反应,这样是不可取的,因此也就是有了信号量这一说。

通过信号量来使线程进入睡眠状态或者唤醒这个线程。

pthread2的更多相关文章

  1. volatile关键字及编译器指令乱序总结

    本文简单介绍volatile关键字的使用,进而引出编译期间内存乱序的问题,并介绍了有效防止编译器内存乱序所带来的问题的解决方法,文中简单提了下CPU指令乱序的现象,但并没有深入讨论. 以下是我搭建的博 ...

  2. GDB深入研究——20135308芦畅

    GDB深入研究 一.GDB代码调试 (一)GDB调试实例 在终端中编译一个示例C语言小程序,保存到文件 gdb-sample.c 中,用GCC编译之 #include <stdio.h> ...

  3. GDB深入研究

    GDB深入研究 一.GDB代码调试 (一)GDB调试实例 在终端中编译一个示例C语言小程序,保存到文件 gdb-sample.c 中,用GCC编译之 #include <stdio.h> ...

  4. Linux进程间通信与线程间同步详解(全面详细)

    引用:http://community.csdn.net/Expert/TopicView3.asp?id=4374496linux下进程间通信的几种主要手段简介: 1. 管道(Pipe)及有名管道( ...

  5. 【转】 Linux 线程同步的三种方法

    线程的最大特点是资源的共享性,但资源共享中的同步问题是多线程编程的难点.linux下提供了多种方式来处理线程同步,最常用的是互斥锁.条件变量和信号量. 一.互斥锁(mutex) 通过锁机制实现线程间的 ...

  6. 【转】 Linux下的多线程编程

    作者:gnuhpc 出处:http://www.cnblogs.com/gnuhpc/原文链接:http://www.cnblogs.com/gnuhpc/archive/2012/12/07/280 ...

  7. Linux下的多线程编程

    1 引言 线程(thread)技术早在60年代就被提出,但真正应用多线程到操作系统中去,是在80年代中期,solaris是这方面的佼佼者.传统的 Unix也支持线程的概念,但是在一个进程(proces ...

  8. pthread_join和pthread_detach的用法(转)

    一:关于join join join是三种同步线程的方式之一.另外两种分别是互斥锁(mutex)和条件变量(condition variable). 调用pthread_join()将阻塞自己,一直到 ...

  9. Linux系统编程@多线程编程(二)

    线程的操作 线程标识 线程的ID表示数据类型:pthread_t (内核中的实现是unsigned long/unsigned int/指向pthread结构的指针(不可移植)几种类型) 1.对两个线 ...

随机推荐

  1. 【原创】Vue项目中各种功能的实现

    已完成: 后台的管理功能: 这里用的组件是 element-UI  ====> NavMenu ◆首先是排版 : <div class="manage-page fillcont ...

  2. C# System.Environment.GetFolderPath的使用 [转]

    原文:https://blog.csdn.net/yongyong521/article/details/75105853 获取系统文件目录 string strPath = Environment. ...

  3. 【BZOJ3205_洛谷3638】[APIO2013]机器人(动态规划)

    题目: 洛谷3638 分析: 卡了一天的神题--(OrzJumpmelon) 首先预处理出从点\(p\)向\(d\)方向出发最终能到达的点\(nxt[p][d]\).这个可以直接记忆化搜索解决.如果出 ...

  4. JAVA中list,set,map与数组之间的转换详解

    package test; import java.util.*; /** * Created by ming */ public class Test { public static void ma ...

  5. easyui form.rest和clear 重置表单和清除表单数据区别

    easyui中的一般我们在新增和编辑的时候 都是用一个form表单 那新增的时候 需要重置下表单内容,一般用 $('#EditForm').form('reset'); 大部分时候没问题,但是如果表单 ...

  6. Android_撕衣服小案例

    一直都觉得做安卓开发挺有意思,最近一段时间都在学习这方面的知识以及练习敲代码这次要说的是一个简单有趣的案例,相信大家也是看了标题才进来的吧,是不是有点迫不及待的想看看效果图,嘿嘿,算了还是直接给上源码 ...

  7. Windows 10 IIS所有的html返回空白

    这是一个神奇的现象.因为使用IIS已经有N多年了,喜欢使用它是因为它随手可得.自从装上windows10以来,直至今天才用它来调试客户端程序.想在上面放一个静态的json数据,省的还要去建立一个Web ...

  8. CentOS 7 使用 yum 安装 MariaDB 与 MariaDB 的简单配置

    闲置已久的空间环境配置忘得差不多了,今天得空整理,重置了磁盘重新搭建环境,首先安装MariaDB的数据库,在这里记录下安装过程,以便以后查看. 1.安装MariaDB 安装命令 yum -y inst ...

  9. (转)Hadoop入门进阶课程

    http://blog.csdn.net/yirenboy/article/details/46800855 1.Hadoop介绍 1.1Hadoop简介 Apache Hadoop软件库是一个框架, ...

  10. CAD实现自定义实体夹点移动(com接口VB语言)

    主要用到函数说明: MxDrawXCustomEvent::MxDrawXCustomEntity::moveGripPointsAt 自定义实体事件,自定义实体夹点被移动,详细说明如下: 参数 说明 ...