互斥锁

1、函数声明

#include <pthread.h>

/* Mutex handling.  */

/* Initialize a mutex.  */
extern int pthread_mutex_init (pthread_mutex_t *__mutex,
__const pthread_mutexattr_t *__mutexattr)
__THROW __nonnull (()); /* Destroy a mutex. */
extern int pthread_mutex_destroy (pthread_mutex_t *__mutex)
__THROW __nonnull (()); /* Try locking a mutex. */
extern int pthread_mutex_trylock (pthread_mutex_t *__mutex)
__THROW __nonnull (()); /* Lock a mutex. */
extern int pthread_mutex_lock (pthread_mutex_t *__mutex)
__THROW __nonnull (());
/* Unlock a mutex. */
extern int pthread_mutex_unlock (pthread_mutex_t *__mutex)
__THROW __nonnull (());

2、函数使用

pthread_mutex_lock(mutex);
// 临界区
// do something....
// 临界区
pthread_mutex_unlock(mutex); /**
* 如果尝试给一个已由另外某个线程锁住的互斥锁上锁
* pthread_mutex_lock将阻塞,直到该互斥锁解锁为止
* pthread_mutex_trylock是对应的非阻塞函数,若互斥锁已锁住,则立即返回一个EBUSY错误
*/

3、测试用例:

/* include main */
#include "unpipc.h" #define MAXNITEMS 1000000
#define MAXNTHREADS 100 int nitems; /* read-only by producer and consumer */
struct
{
pthread_mutex_t mutex;
int buff[MAXNITEMS];
int nput; // 记录已写条目数目
int nval;
} shared = { PTHREAD_MUTEX_INITIALIZER }; void *produce(void *);
void *consume(void *); int main(int argc, char **argv)
{
int i, nthreads, count[MAXNTHREADS];
pthread_t tid_produce[MAXNTHREADS]; // 多生产者线程
pthread_t tid_consume; // 单消费者线程 if (argc != )
err_quit("usage: prodcons2 <#items> <#threads>");
nitems = min(atoi(argv[]), MAXNITEMS);
nthreads = min(atoi(argv[]), MAXNTHREADS); /* 最好调用pthread_setconcurrency函数 */
Set_concurrency(nthreads); // 设置并行级别,大部分系统中该函数并没有什么作用
/* 4start all the producer threads */
for (i = ; i < nthreads; i++)
{
count[i] = ;
Pthread_create(&tid_produce[i], NULL, produce, &count[i]);
} /* 4wait for all the producer threads */
for (i = ; i < nthreads; i++)
{
Pthread_join(tid_produce[i], NULL);
printf("count[%d] = %d\n", i, count[i]);
} /* 4start, then wait for the consumer thread */
Pthread_create(&tid_consume, NULL, consume, NULL);
Pthread_join(tid_consume, NULL); exit();
}
/* end main */ /* include producer */
void *produce(void *arg)
{
for ( ; ; )
{
Pthread_mutex_lock(&shared.mutex);
if (shared.nput >= nitems)
{
Pthread_mutex_unlock(&shared.mutex);
return(NULL); /* array is full, we're done */
}
shared.buff[shared.nput] = shared.nval;
shared.nput++;
shared.nval++;
Pthread_mutex_unlock(&shared.mutex);
*((int *) arg) += ; // 每个线程修改各自的元素
}
} void *consume(void *arg)
{
int i; for (i = ; i < nitems; i++)
{
if (shared.buff[i] != i)
printf("buff[%d] = %d\n", i, shared.buff[i]);
}
return(NULL);
}
/* end producer */

条件变量

互斥锁用于上锁,条件变量用于等待,这是两种不同类型的同步。

1、函数声明

#include  <pthread.h>

/* Wake up one thread waiting for condition variable COND.  */
extern int pthread_cond_signal (pthread_cond_t *__cond)
__THROW __nonnull (()); /* Wake up all threads waiting for condition variables COND. */
extern int pthread_cond_broadcast (pthread_cond_t *__cond)
__THROW __nonnull (()); /* Wait for condition variable COND to be signaled or broadcast.
MUTEX is assumed to be locked before. This function is a cancellation point and therefore not marked with
__THROW. */
extern int pthread_cond_wait (pthread_cond_t *__restrict __cond,
pthread_mutex_t *__restrict __mutex)
__nonnull ((, )); /* Wait for condition variable COND to be signaled or broadcast until
ABSTIME. MUTEX is assumed to be locked before. ABSTIME is an
absolute time specification; zero is the beginning of the epoch
(00:00:00 GMT, January 1, 1970). This function is a cancellation point and therefore not marked with
__THROW. */
extern int pthread_cond_timedwait (pthread_cond_t *__restrict __cond,
pthread_mutex_t *__restrict __mutex,
__const struct timespec *__restrict
__abstime) __nonnull ((, , ));

2、函数使用

struct
{
pthread_mutex_t mutex;
pthread_cond_t cond;
// ...
} var = { PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER }; /**
* 给条件变量发送信号代码
*/
Pthread_mutex_lock(&var.mutex);
if(condition0 == true)
{
Pthread_cond_signal(&var.cond);
}
// do something...
pthread_mutex_unlock(&var.mutex); /**
* 测试条件变量
*/
Pthread_mutex_lock(&var.mutex);
while(condition1 == false) // 防止接收到错误信号
{
Pthread_cond_wait(&var.cond, &var.mutex);
}
// do something...
pthread_mutex_unlock(&var.mutex);

关于Pthread_cond_wait(&var.cond, &var.mutex)函数的说明

The mutex passed to pthread_cond_wait protects the condition.The caller passes it locked to the function, which then atomically places them calling thread on the list of threads waiting for the condition and unlocks the mutex. This closes the window between the time that the condition is checked and the time that the thread goes to sleep waiting for the condition to change, so that the thread doesn't miss a change in the condition. When pthread_cond_wait returns, the mutex is again locked.

上面是APUE的原话,就是说pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)函数传入的参数mutex用于保护条件,因为我们在调用pthread_cond_wait时,如果条件不成立我们就进入阻塞,但是进入阻塞这个期间,如果条件变量改变了的话,那我们就漏掉了这个条件。因为这个线程还没有放到等待队列上,所以调用pthread_cond_wait前要先锁互斥量,即调用pthread_mutex_lock(),pthread_cond_wait在把线程放进阻塞队列后,自动对mutex进行解锁,使得其它线程可以获得加锁的权利。这样其它线程才能对临界资源进行访问并在适当的时候唤醒这个阻塞的进程。当pthread_cond_wait返回的时候又自动给mutex加锁。
// 函数执行期间锁的调用(伪码)
lock(mutex) ----------------a.lock pthread_cond_wait()
{
unlock(mutex)-------------a.unlock
if (条件不满足)
suspend();
else
{
lock(mutex)-------------b.lock
return
}
} dosomething(); unlock(mutex);---------------b.unlock

3、测试用例

/* include globals */
#include "unpipc.h" #define MAXNITEMS 1000000
#define MAXNTHREADS 100 /* globals shared by threads */
int nitems; /* read-only by producer and consumer */
int buff[MAXNITEMS];
struct
{
pthread_mutex_t mutex;
int nput; /* next index to store */
int nval; /* next value to store */
} put = { PTHREAD_MUTEX_INITIALIZER }; struct
{
pthread_mutex_t mutex;
pthread_cond_t cond;
int nready; /* number ready for consumer */
} nready = { PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER };
/* end globals */ void *produce(void *);
void *consume(void *); /* include main */
int
main(int argc, char **argv)
{
int i, nthreads, count[MAXNTHREADS];
pthread_t tid_produce[MAXNTHREADS], tid_consume; if (argc != )
err_quit("usage: prodcons6 <#items> <#threads>");
nitems = min(atoi(argv[]), MAXNITEMS);
nthreads = min(atoi(argv[]), MAXNTHREADS); Set_concurrency(nthreads + );
/* 4create all producers and one consumer */
for (i = ; i < nthreads; i++)
{
count[i] = ;
Pthread_create(&tid_produce[i], NULL, produce, &count[i]);
}
Pthread_create(&tid_consume, NULL, consume, NULL); /* wait for all producers and the consumer */
for (i = ; i < nthreads; i++)
{
Pthread_join(tid_produce[i], NULL);
printf("count[%d] = %d\n", i, count[i]);
}
Pthread_join(tid_consume, NULL); exit();
}
/* end main */ /* include prodcons */
void *
produce(void *arg)
{
for ( ; ; )
{
Pthread_mutex_lock(&put.mutex);
if (put.nput >= nitems)
{
Pthread_mutex_unlock(&put.mutex);
return(NULL); /* array is full, we're done */
}
buff[put.nput] = put.nval;
put.nput++;
put.nval++;
Pthread_mutex_unlock(&put.mutex); /* 同步生产者与消费者线程 */
Pthread_mutex_lock(&nready.mutex);
if (nready.nready == )
{
// 发送信号,系统调用等待在nready.cond上的线程
// 该线程开始运行,但是立即停止,因为无法获取nready.mutex锁
Pthread_cond_signal(&nready.cond);
} nready.nready++;
Pthread_mutex_unlock(&nready.mutex); *((int *) arg) += ;
}
} void *
consume(void *arg)
{
int i; for (i = ; i < nitems; i++)
{
Pthread_mutex_lock(&nready.mutex);
while (nready.nready == ) // 当产品数目为0时才会有线程阻塞,此时采用必要发送条件信号
{
Pthread_cond_wait(&nready.cond, &nready.mutex);
} nready.nready--;
Pthread_mutex_unlock(&nready.mutex); if (buff[i] != i)
printf("buff[%d] = %d\n", i, buff[i]);
}
return(NULL);
}
/* end prodcons */

Unix IPC之互斥锁与条件变量的更多相关文章

  1. node源码详解(七) —— 文件异步io、线程池【互斥锁、条件变量、管道、事件对象】

    本作品采用知识共享署名 4.0 国际许可协议进行许可.转载保留声明头部与原文链接https://luzeshu.com/blog/nodesource7 本博客同步在https://cnodejs.o ...

  2. 进程间通信机制(管道、信号、共享内存/信号量/消息队列)、线程间通信机制(互斥锁、条件变量、posix匿名信号量)

    注:本分类下文章大多整理自<深入分析linux内核源代码>一书,另有参考其他一些资料如<linux内核完全剖析>.<linux c 编程一站式学习>等,只是为了更好 ...

  3. linux c 线程间同步(通信)的几种方法--互斥锁,条件变量,信号量,读写锁

    Linux下提供了多种方式来处理线程同步,最常用的是互斥锁.条件变量.信号量和读写锁. 下面是思维导图:  一.互斥锁(mutex)  锁机制是同一时刻只允许一个线程执行一个关键部分的代码. 1 . ...

  4. 非常精简的Linux线程池实现(一)——使用互斥锁和条件变量

    线程池的含义跟它的名字一样,就是一个由许多线程组成的池子. 有了线程池,在程序中使用多线程变得简单.我们不用再自己去操心线程的创建.撤销.管理问题,有什么要消耗大量CPU时间的任务通通直接扔到线程池里 ...

  5. linux 线程的同步 二 (互斥锁和条件变量)

    互斥锁和条件变量 为了允许在线程或进程之间共享数据,同步时必须的,互斥锁和条件变量是同步的基本组成部分. 1.互斥锁 互斥锁是用来保护临界区资源,实际上保护的是临界区中被操纵的数据,互斥锁通常用于保护 ...

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

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

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

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

  8. linux 互斥锁和条件变量

    为什么有条件变量? 请参看一个线程等待某种事件发生 注意:本文是linux c版本的条件变量和互斥锁(mutex),不是C++的. mutex : mutual exclusion(相互排斥) 1,互 ...

  9. 线程私有数据TSD——一键多值技术,线程同步中的互斥锁和条件变量

    一:线程私有数据: 线程是轻量级进程,进程在fork()之后,子进程不继承父进程的锁和警告,别的基本上都会继承,而vfork()与fork()不同的地方在于vfork()之后的进程会共享父进程的地址空 ...

随机推荐

  1. 解题:NOI 2016 优秀的拆分

    题面 其实题目不算很难,但是我调试的时候被玄学了,for循环里不写空格会RE,写了才能过.神**调了一个多小时是这么个不知道是什么的玩意(真事,可以问i207M=.=),心态爆炸 发现我们只要找AA或 ...

  2. 《剑指offer》— JavaScript(15)反转链表

    反转链表 题目描述 输入一个链表,反转链表后,输出链表的所有元素. *** 思路 (本题链表默认无头结点) pHead为当前结点,如果当前结点为空的话,直接返回: pHead为当前结点,pre为当前结 ...

  3. Java基础-IO流对象之字节缓冲流(BufferedOutputStream与BufferedInputStream)

    Java基础-IO流对象之字节缓冲流(BufferedOutputStream与BufferedInputStream) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 在我们学习字 ...

  4. 页面缓存之Meta http-equiv属性详解

    http-equiv顾名思义,相当于http的文件头作用,它可以向浏览器传回一些有用的信息,以帮助正确和精确地显示网页内容,与之对应的属性值为content,content中的内容其实就是各个参数的变 ...

  5. [非常重要的总结] Linux C相关函数

    (1)字符测试函数 isalnum(测试字符是否为英文字母或数字) isalpha(测试字符是否为英文字母) isascii(测试字符是否为ASCII码字符) isblank(测试字符是否为空格字符) ...

  6. HDU 5985 概率

    n种硬币各有cnt[i]枚,每轮下其有p[i]概率保留,问各种硬币只有它存活到最后一轮的概率. 设k轮后i硬币存活概率$a[i][k]=(1-p^k_i)^{cnt[i]}$ 则最后只有第i种硬币存活 ...

  7. HDU 3802 矩阵快速幂 化简递推式子 加一点点二次剩余知识

    求$G(a,b,n,p) = (a^{\frac {p-1}{2}}+1)(b^{\frac{p-1}{2}}+1)[(\sqrt{a} + \sqrt{b})^{2F_n} + (\sqrt{a} ...

  8. excel sum求和遇到的问题及解决

    在偶遇的,借助excel公式sum对一个数字数组进行求和,结果为0,很是诧异,当然原因就是,数组里的数字是“常规”格式,不是“数值”格式,由于系统生成的excel,不方便生成的同时再做格式的设置,于是 ...

  9. css 系统自学笔记2017-12-04

    一.几个常用的可以连写的样式属性 1.backgroud: 背景连写:没有先后顺序,都是可选的. 2.font字体属性连写: font: 二.元素分类 块级元素:div p h1~h6 ul li o ...

  10. 你应该了解的强大CSS表达式 ----- expression

    IE5及其以后版本支持在CSS中使用expression,用来把CSS属性和Javas cript表达式关联起来,这里的CSS属性可以是元素固有的属性,也可以是自定义属性.就是说CSS属性后面可以是一 ...