Linux下为了多线程同步,通常用到锁的概念。
posix下抽象了一个锁类型的结构:ptread_mutex_t。通过对该结构的操作,来判断资源是否可以访问。顾名思义,加锁(lock)后,别人就无法打开,只有当锁没有关闭(unlock)的时候才能访问资源。

即对象互斥锁的概念,来保证共享数据操作的完整性。每个对象都对应于一个可称为" 互斥锁" 的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。

使用互斥锁(互斥)可以使线程按顺序执行。通常,互斥锁通过确保一次只有一个线程执行代码的临界段来同步多个线程。互斥锁还可以保护单线程代码。

  要更改缺省的互斥锁属性,可以对属性对象进行声明和初始化。通常,互斥锁属性会设置在应用程序开头的某个位置,以便可以快速查找和轻松修改。

1.函数原型:

int pthread_mutex_init(pthread_mutex_t *restrict mutex,
              const pthread_mutexattr_t *restrict attr);

该函数用于C函数的多线程编程中,互斥锁的初始化。

  pthread_mutex_init()函数是以动态方式创建互斥锁的,参数attr指定了新建互斥锁的属性。如果参数attr为NULL,则使用默认的互斥锁属性,默认属性为快速互斥锁 。互斥锁的属性在创建锁的时候指定,在LinuxThreads实现中仅有一个锁类型属性,不同的锁类型在试图对一个已经被锁定的互斥锁加锁时表现不同。

  pthread_mutexattr_init()函数成功完成之后会返回零,其他任何返回值都表示出现了错误。

  函数成功执行后,互斥锁被初始化为锁住态。

 2. 互斥锁属性

互斥锁的属性在创建锁的时候指定,在LinuxThreads实现中仅有一个锁类型属性,不同的锁类型在试图对一个已经被锁定的互斥锁加锁时表现不同。当前(glibc2.2.3,linuxthreads0.9)有四个值可供选择:

  * PTHREAD_MUTEX_TIMED_NP,这是缺省值,也就是普通锁。当一个线程加锁以后,其余请求锁的线程将形成一个等待队列,并在解锁后按优先级获得锁。这种锁策略保证了资源分配的公平性。

  * PTHREAD_MUTEX_RECURSIVE_NP,嵌套锁,允许同一个线程对同一个锁成功获得多次,并通过多次unlock解锁。如果是不同线程请求,则在加锁线程解锁时重新竞争。

  * PTHREAD_MUTEX_ERRORCHECK_NP,检错锁,如果同一个线程请求同一个锁,则返回EDEADLK,否则与PTHREAD_MUTEX_TIMED_NP类型动作相同。这样就保证当不允许多次加锁时不会出现最简单情况下的死锁。

  * PTHREAD_MUTEX_ADAPTIVE_NP,适应锁,动作最简单的锁类型,仅等待解锁后重新竞争。

3. 其他锁操作

  锁操作主要包括加锁pthread_mutex_lock()、解锁pthread_mutex_unlock()和测试加锁 pthread_mutex_trylock()三个,不论哪种类型的锁,都不可能被两个不同的线程同时得到,而必须等待解锁。对于普通锁和适应锁类型,解锁者可以是同进程内任何线程;而检错锁则必须由加锁者解锁才有效,否则返回EPERM;对于嵌套锁,文档和实现要求必须由加锁者解锁,但实验结果表明并没有这种限制,这个不同目前还没有得到解释。在同一进程中的线程,如果加锁后没有解锁,则任何其他线程都无法再获得锁。

int pthread_mutex_lock(pthread_mutex_t *mutex)

  int pthread_mutex_unlock(pthread_mutex_t *mutex)

  int pthread_mutex_trylock(pthread_mutex_t *mutex)

  pthread_mutex_trylock()语义与pthread_mutex_lock()类似,不同的是在锁已经被占据时返回EBUSY而不是挂起等待。

4. 死锁:

  死锁主要发生在有多个依赖锁存在时, 会在一个线程试图以与另一个线程相反顺序锁住互斥量时发生. 如何避免死锁是使用互斥量应该格外注意的东西。

  总体来讲, 有几个不成文的基本原则:

  对共享资源操作前一定要获得锁。

  完成操作以后一定要释放锁。

  尽量短时间地占用锁。

  如果有多锁, 如获得顺序是ABC连环扣, 释放顺序也应该是ABC。

  线程错误返回时应该释放它所获得的锁。

下面是一段测试代码,创建两个线程,分别访问全局变量gnum,并且修改它,打印出来

/*mutex.c*/
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <errno.h>
/*全局变量*/
int gnum = 0;
/*互斥量 */
pthread_mutex_t mutex;
/*声明线程运行服务程序*/
static void pthread_func_1 (void);
static void pthread_func_2 (void);

int main (void)
{
 /*线程的标识符*/
  pthread_t pt_1 = 0;
  pthread_t pt_2 = 0;
  int ret = 0;
  /*互斥初始化*/
  pthread_mutex_init (&mutex, NULL);
  /*分别创建线程1、2*/
  ret = pthread_create( &pt_1,                  //线程标识符指针
                                     NULL,                  //默认属性
                                     (void *)pthread_func_1,//运行函数
                                     NULL);                  //无参数
  if (ret != 0)
  {
     perror ("pthread_1_create");
  }

ret = pthread_create( &pt_2,                  //线程标识符指针
                                     NULL,                   //默认属性
                                     (void *)pthread_func_2, //运行函数
                                     NULL);                  //无参数
  if (ret != 0)
  {
     perror ("pthread_2_create");
  }
  /*等待线程1、2的结束*/
  pthread_join (pt_1, NULL);
  pthread_join (pt_2, NULL);

printf ("main programme exit!/n");
  return 0;
}
/*线程1的服务程序*/
static void pthread_func_1 (void)
{
  int i = 0;

for( i=0; i<3; i++ ){
    printf ("This is pthread_1!/n");
    pthread_mutex_lock(&mutex); /*获取互斥锁*/
        /*注意,这里以防线程的抢占,以造成一个线程在另一个线程sleep时多次访问互斥资源,所以sleep要在得到互斥锁后调用*/
    sleep (1);
    /*临界资源*/
    gnum++;
    printf ("Thread_1 add one to num:%d/n",gnum);
    pthread_mutex_unlock(&mutex); /*释放互斥锁*/
  }

pthread_exit ( NULL );
}
/*线程2的服务程序*/
static void pthread_func_2 (void)
{
  int i = 0;

for( i=0; i<5; i++ )  {
    printf ("This is pthread_2!/n");
    pthread_mutex_lock(&mutex); /*获取互斥锁*/
        /*注意,这里以防线程的抢占,以造成一个线程在另一个线程sleep时多次访问互斥资源,所以sleep要在得到互斥锁后调用*/
    sleep (1);
    /*临界资源*/
    gnum++;
    printf ("Thread_2 add one to num:%d/n",gnum);
    pthread_mutex_unlock(&mutex); /*释放互斥锁*/

}

pthread_exit ( NULL );
}

参考来源于网络:

http://baike.baidu.com/view/4518300.html

http://baike.baidu.com/view/1461738.htm

http://blog.csdn.net/benny_cen/article/details/3969219

http://blog.csdn.net/xing_hao/article/details/6626223

http://hi.baidu.com/cunlin/blog/item/1f9e3f384c6bbeffb211c79c.html

http://blog.chinaunix.net/space.php?uid=20698441&do=blog&id=1891215

互斥锁 pthread_mutex_init()函数的更多相关文章

  1. 互斥锁pthread_mutex_init()函数

    linux下为了多线程同步,通常用到锁的概念.posix下抽象了一个锁类型的结构:ptread_mutex_t.通过对该结构的操作,来判断资源是否可以访问.顾名思义,加锁(lock)后,别人就无法打开 ...

  2. Linux互斥锁、条件变量和信号量

    Linux互斥锁.条件变量和信号量  来自http://kongweile.iteye.com/blog/1155490 http://www.cnblogs.com/qingxia/archive/ ...

  3. linux 2.6 互斥锁的实现-源码分析

    http://blog.csdn.net/tq02h2a/article/details/4317211 看了看linux 2.6 kernel的源码,下面结合代码来分析一下在X86体系结构下,互斥锁 ...

  4. 【TencentOS tiny】深度源码分析(6)——互斥锁

    互斥锁 互斥锁又称互斥互斥锁,是一种特殊的信号量,它和信号量不同的是,它具有互斥锁所有权.递归访问以及优先级继承等特性,在操作系统中常用于对临界资源的独占式处理.在任意时刻互斥锁的状态只有两种,开锁或 ...

  5. 鸿蒙内核源码分析(互斥锁篇) | 比自旋锁丰满的互斥锁 | 百篇博客分析OpenHarmony源码 | v27.02

    百篇博客系列篇.本篇为: v27.xx 鸿蒙内核源码分析(互斥锁篇) | 比自旋锁丰满的互斥锁 | 51.c.h .o 进程通讯相关篇为: v26.xx 鸿蒙内核源码分析(自旋锁篇) | 自旋锁当立贞 ...

  6. pthread_mutex_init & 互斥锁pthread_mutex_t的使用

    pthread_mutex_init l         头文件: #include <pthread.h> l         函数原型: int pthread_mutex_init( ...

  7. 子进程回收资源两种方式,僵尸进程与孤儿进程,守护进程,进程间数据隔离,进程互斥锁,队列,IPC机制,线程,守护线程,线程池,回调函数add_done_callback,TCP服务端实现并发

    子进程回收资源两种方式 - 1) join让主进程等待子进程结束,并回收子进程资源,主进程再结束并回收资源. - 2) 主进程 “正常结束” ,子进程与主进程一并被回收资源. from multipr ...

  8. Python进阶----线程基础,开启线程的方式(类和函数),线程VS进程,线程的方法,守护线程,详解互斥锁,递归锁,信号量

    Python进阶----线程基础,开启线程的方式(类和函数),线程VS进程,线程的方法,守护线程,详解互斥锁,递归锁,信号量 一丶线程的理论知识 什么是线程:    1.线程是一堆指令,是操作系统调度 ...

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

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

随机推荐

  1. HDU 3811 Permutation 状压dp

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3811 Permutation Time Limit: 6000/3000 MS (Java/Othe ...

  2. 第一次spring冲刺第9天

    明天是这个阶段的最后一天了,今天讨论关于容错的方面,例如输入空白或其他字符等方面会出现的问题 ,部分代码如下: public void checkout(int trueResult) { Strin ...

  3. 《TCP/IP 详解 卷1:协议》第 11 章:名称解析和域名系统

    引言 到目前为止,我们使用 IP 地址来研究参与网络的主机.对于大众来说,这些地址太繁琐且难以记忆.为了使用如 TCP 和 IP 等协议,主机名称通过名为名称解析(name resolution)的过 ...

  4. Java基本程序设计结构

    一.要求: 1.设平面上有一个m×n 的网格,将左下角的网格点标记为(0,0)而右上角的网格点标记为(m,n).某人想从(0,0)出发沿网格线行进到达(m,n),但是在网格点(i,j)处他只能向上行进 ...

  5. [BUAA_SE_2017]个人阅读作业 + 总结

    个人阅读作业 银弹 银弹是指能让狼人一枪毙命的致命子弹,对于软件工程而言,我觉得是不存在银弹的.每一项软件开发都是极为特殊的,有特定的需求.特定的功能,如果存在银弹能够直击要害解决问题,那么软件的开发 ...

  6. Hive如何加载和导入HBase的数据

    当我们用HBase 存储实时数据的时候, 如果要做一些数据分析方面的操作, 就比较困难了, 要写MapReduce Job. Hive 主要是用来做数据分析的数据仓库,支持标准SQL 查询, 做数据分 ...

  7. 设置session的过期时间

    1)修改php.ini文件中的gc_maxlifetime变量就可以延长session的过期时间了 session.gc_maxlifetime = 86400 然后,重启你的web服务(一般是apa ...

  8. Python Matplotlib绘图库 安装

    一般我们在做科学计算的时候,首先会想到的是matlab,但是呢,一想到matlab安装包那么大,我就有点不想说什么了. Matplotlib 是python最著名的绘图库,它提供了一整套和matlab ...

  9. jmete JSR223 PostProcessor使用

    1.使用xpath Extractor提取页面值 2.使用 JSR223 PostProcessor拼接json数据 function genJsons() { var MaterialName = ...

  10. 用join取代not in

    写了好几个页面,速度都上不去,瓶颈在于SQL查询.太多的表,太多的not in,总是从一大推表和数据中筛选出一点数据.看了很多关于SQL优化的文章,都强烈要求不要太多使用not in查询,最好用表连接 ...