互斥锁pthread_mutex_init()函数
linux下为了多线程同步,通常用到锁的概念。
posix下抽象了一个锁类型的结构:ptread_mutex_t。通过对该结构的操作,来判断资源是否可以访问。顾名思义,加锁(lock)后,别人就无法打开,只有当锁没有关闭(unlock)的时候才能访问资源。
即对象互斥锁的概念,来保证共享数据操作的完整性。每个对象都对应于一个可称为" 互斥锁" 的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。
使用互斥锁(互斥)可以使线程按顺序执行。通常,互斥锁通过确保一次只有一个线程执行代码的临界段来同步多个线程。互斥锁还可以保护单线程代码。
要更改缺省的互斥锁属性,可以对属性对象进行声明和初始化。通常,互斥锁属性会设置在应用程序开头的某个位置,以便可以快速查找和轻松修改。
l 头文件:
#include <pthread.h>
l 函数原型:
int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
l 函数作用:
该函数用于C函数的多线程编程中,互斥锁的初始化。
pthread_mutex_init() 函数是以动态方式创建互斥锁的,参数attr指定了新建互斥锁的属性。如果参数attr为空(NULL),则使用默认的互斥锁属性,默认属性为快速互斥锁 。互斥锁的属性在创建锁的时候指定,在LinuxThreads实现中仅有一个锁类型属性,不同的锁类型在试图对一个已经被锁定的互斥锁加锁时表现不同。
pthread_mutexattr_init() 函数成功完成之后会返回零,其他任何返回值都表示出现了错误。
函数成功执行后,互斥锁被初始化为未锁住态。
l 互斥锁pthread_mutex_t的使用:
1. 互斥锁创建和销毁
有两种方法创建互斥锁,静态方式和动态方式。POSIX定义了一个宏PTHREAD_MUTEX_INITIALIZER来静态初始化互斥锁,方法如下:
pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;
在LinuxThreads实现中,pthread_mutex_t是一个结构,而PTHREAD_MUTEX_INITIALIZER则是一个结构常量。
动态方式是采用pthread_mutex_init()函数来初始化互斥锁,API定义如下:
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr)
其中mutexattr用于指定互斥锁属性(见下),如果为NULL则使用缺省属性。
pthread_mutex_destroy()用于注销一个互斥锁,API定义如下:
int pthread_mutex_destroy(pthread_mutex_t *mutex)
销毁一个互斥锁即意味着释放它所占用的资源,且要求锁当前处于开放状态。由于在Linux中,互斥锁并不占用任何资源,因此LinuxThreads中的 pthread_mutex_destroy()除了检查锁状态以外(锁定状态则返回EBUSY)没有其他动作。
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 = ;
/* 互斥量 */
pthread_mutex_t mutex; /* 声明线程运行服务程序. */
static void pthread_func_1(void);
static void pthread_func_2(void); int main (void)
{
/*线程的标识符*/
pthread_t pt_1 = ;
pthread_t pt_2 = ;
int ret = ; /* 互斥初始化. */
pthread_mutex_init(&mutex, NULL);
/*分别创建线程1、2*/
ret = pthread_create(&pt_1, //线程标识符指针
NULL, //默认属性
(void*)pthread_func_1, //运行函数
NULL); //无参数
if (ret != )
{
perror ("pthread_1_create");
} ret = pthread_create(&pt_2, //线程标识符指针
NULL, //默认属性
(void *)pthread_func_2, //运行函数
NULL); //无参数
if (ret != )
{
perror ("pthread_2_create");
}
/*等待线程1、2的结束*/
pthread_join(pt_1, NULL);
pthread_join(pt_2, NULL); printf ("main programme exit!/n");
return ;
} /*线程1的服务程序*/
static void pthread_func_1(void)
{
int i = ; for (i=; i<; i++) {
printf ("This is pthread_1!/n");
pthread_mutex_lock(&mutex); /* 获取互斥锁 */
/* 注意,这里以防线程的抢占,以造成一个线程在另一个线程sleep时多次访问互斥资源,所以sleep要在得到互斥锁后调用. */
sleep ();
/*临界资源*/
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 = ; for (i=; i<; i++) {
printf ("This is pthread_2!/n");
pthread_mutex_lock(&mutex); /* 获取互斥锁. */
/* 注意,这里以防线程的抢占,以造成一个线程在另一个线程sleep时多次访问互斥资源,所以sleep要在得到互斥锁后调用. */
sleep();
/* 临界资源. */
gnum++;
printf ("Thread_2 add one to num:%d/n",gnum);
pthread_mutex_unlock(&mutex); /* 释放互斥锁. */
} pthread_exit (NULL);
}
互斥锁pthread_mutex_init()函数的更多相关文章
- 互斥锁 pthread_mutex_init()函数
		Linux下为了多线程同步,通常用到锁的概念.posix下抽象了一个锁类型的结构:ptread_mutex_t.通过对该结构的操作,来判断资源是否可以访问.顾名思义,加锁(lock)后,别人就无法打开 ... 
- Linux互斥锁、条件变量和信号量
		Linux互斥锁.条件变量和信号量 来自http://kongweile.iteye.com/blog/1155490 http://www.cnblogs.com/qingxia/archive/ ... 
- linux 2.6 互斥锁的实现-源码分析
		http://blog.csdn.net/tq02h2a/article/details/4317211 看了看linux 2.6 kernel的源码,下面结合代码来分析一下在X86体系结构下,互斥锁 ... 
- 【TencentOS  tiny】深度源码分析(6)——互斥锁
		互斥锁 互斥锁又称互斥互斥锁,是一种特殊的信号量,它和信号量不同的是,它具有互斥锁所有权.递归访问以及优先级继承等特性,在操作系统中常用于对临界资源的独占式处理.在任意时刻互斥锁的状态只有两种,开锁或 ... 
- 鸿蒙内核源码分析(互斥锁篇) | 比自旋锁丰满的互斥锁 | 百篇博客分析OpenHarmony源码 | v27.02
		百篇博客系列篇.本篇为: v27.xx 鸿蒙内核源码分析(互斥锁篇) | 比自旋锁丰满的互斥锁 | 51.c.h .o 进程通讯相关篇为: v26.xx 鸿蒙内核源码分析(自旋锁篇) | 自旋锁当立贞 ... 
- pthread_mutex_init & 互斥锁pthread_mutex_t的使用
		pthread_mutex_init l 头文件: #include <pthread.h> l 函数原型: int pthread_mutex_init( ... 
- 子进程回收资源两种方式,僵尸进程与孤儿进程,守护进程,进程间数据隔离,进程互斥锁,队列,IPC机制,线程,守护线程,线程池,回调函数add_done_callback,TCP服务端实现并发
		子进程回收资源两种方式 - 1) join让主进程等待子进程结束,并回收子进程资源,主进程再结束并回收资源. - 2) 主进程 “正常结束” ,子进程与主进程一并被回收资源. from multipr ... 
- Python进阶----线程基础,开启线程的方式(类和函数),线程VS进程,线程的方法,守护线程,详解互斥锁,递归锁,信号量
		Python进阶----线程基础,开启线程的方式(类和函数),线程VS进程,线程的方法,守护线程,详解互斥锁,递归锁,信号量 一丶线程的理论知识 什么是线程: 1.线程是一堆指令,是操作系统调度 ... 
- linux c学习笔记----互斥锁属性
		转自:http://lobert.iteye.com/blog/1762844 互斥锁属性 使用互斥锁(互斥)可以使线程按顺序执行.通常,互斥锁通过确保一次只有一个线程执行代码的临界段来同步多个线程. ... 
随机推荐
- Qt Installer Framework 使用说明(三)
			目录 6.Qt Installer Framework 示例 7.参考 Reference 配置文件 Configuration File 配置文件元素的简要说明 Summary of Configu ... 
- db_table--Spring Security3.1 最新配置实例
			2011-04-28 这几天学习了一下Spring Security3.1,从官网下载了Spring Security3.1版本进行练习,经过多次尝试才摸清了其中的一些原理.本人不才,希望能帮助大家. ... 
- hql语句的case when then else end问题
			http://www.iteye.com/problems/4499 hibernate count不支持case when? 
- javascript中的复制
			github 深度复制这个问题看似简单,实际上要想完美实现需要很多知识. 需要考虑Set,Map,Promise等类型的对象 这个库简洁明了,是一个小巧玲珑的JS库 Promise简单例子 funct ... 
- java struts2入门学习--OGNL语言常用符号和常用标签学习
			一.OGNL常用符号(接上一篇文章): 1.#号 1)<s:property value="#request.username"/> 作用于struts2的域对象,而不 ... 
- linux 的时区设置函数tzset()  【转】
			linux 的时区设置函数tzset() 本文转载于: http://blog.csdn.net/epicyong333/article/details/5258152 tzset #incude & ... 
- MySQL高可用性大杀器之MHA
			MySQL高可用性大杀器之MHA 提到MySQL高可用性,很多人会想到MySQL Cluster,亦或者Heartbeat+DRBD,不过这些方案的复杂性常常让人望而却步,与之相对,利用MySQL ... 
- httpd: Could not reliably determine the server's fully qualified domain name(转)
			ttpd: Could not reliably determine the server's fully qualified domain name, using 127.0.0.1 for Ser ... 
- mysql远程访问,修改root密码
			mysql -uroot -p #input password use mysql; update user set host='%' where user='root'; flush privile ... 
- mvc 权限验证
			using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.We ... 
