pthread 互斥量
参考文献:
温故知新
在 OS 中,每个进程都独立地拥有:
- Process ID, process group ID, user ID, and group ID
- Environment
- Working directory
- Program instructions
- Registers
- Stack
- Heap
- File descriptors
- Signal actions
- Shared libraries
- Inter-process communication tools (such as message queues, pipes, semaphores, or shared memory).
因此,使用 fork
开启一个新的进程,需要拷贝很多数据,开销较大。
与进程不同,线程需要只需要独立拥有:
- Stack pointer
- Registers
- Scheduling properties (such as policy or priority)
- Set of pending and blocked signals
- Thread specific data
需要特别注意的是,文件描述符和堆空间是进程独有的,因此该进程下面的所有线程都共用该进程的堆与文件描述符。
例如下面的代码:
#include <stdlib.h>
#include <pthread.h>
#include <stdio.h>
#include <string.h>
void *worker1(void *arg)
{
char *p = malloc(25);
memcpy(p, "heap data from worker1", 23);
return p;
};
void *worker2(void *arg)
{
pthread_t tid1 = *(pthread_t *)arg;
char *ptr = NULL;
pthread_join(tid1, (void **)&ptr);
printf("In worker2: ");
if (ptr) puts(ptr);
return NULL;
}
int main()
{
pthread_t tid1, tid2;
pthread_create(&tid1, NULL, worker1, NULL);
pthread_create(&tid2, NULL, worker2, &tid1);
pthread_join(tid2, NULL);
}
线程同步
在描述这个概念之前,先看一段代码:
#include <stdlib.h>
#include <pthread.h>
#include <stdio.h>
#include <string.h>
const int N = 1e4;
int value = 0;
void *worker1(void *arg)
{
int i = 1;
for (; i <= N / 2; i++) value = value + i;
return NULL;
};
void *worker2(void *arg)
{
int i = N / 2 + 1;
for (; i <= N; i++) value = value + i;
return NULL;
}
int main()
{
pthread_t tid1, tid2;
pthread_create(&tid1, NULL, worker1, NULL);
pthread_create(&tid2, NULL, worker2, NULL);
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
printf("%d\n", value);
printf("SUM(1, %d) should be %d .\n", N, N * (N + 1) / 2);
}
显然,我们想通过 2 个线程实现 SUM(1, N)
这个功能,但是编译多次你会发现,value
的值并不准确,有时候能输出正确答案 500500
,有时候却不能。
这是因为 work1
和 work2
是并发执行的,假设一开始,2 个线程同时计算 value + i
,work1
和 work2
分别得到 1
和 5001
,但是写入 value
变量是有先后顺序的。假设 work1
先写入,work2
后写入,那么对于这 2 次累加,value
的最终结果是 5001
,而不是 5002
。
从这个例子可以看出,线程与进程类似,同样需要同步 (Synchronization) ,对于临界资源,每次只允许一个线程访问。
互斥量 mutex
互斥量,也叫互斥锁。mutex, 即 Mutual exclusion , 意为相互排斥,主要用于实现线程同步中的写保护操作。
pthread_mutex_init
初始化一个互斥量 pthread_mutex_t mutex
.
函数原型:
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);
参数:
mutex
是即将要被初始化的互斥量attr
是互斥量的属性,与pthread_attr_t
类似
与之类似的,还有 pthread_mutex_destroy
函数。
使用方法:
pthread_mutex_t mutex;
pthread_mutex_init(&mutex, NULL);
pthread_mutex_destroy(&mutex);
pthread_mutex_lock
阻塞调用。如果这个互斥锁此时正在被其它线程占用, 那么 pthread_mutex_lock()
调用会进入到这个互斥锁量的等待队列中,并会进入阻塞状态, 直到拿到该锁之后才会返回。
函数原型如下:
int pthread_mutex_lock(pthread_mutex_t *mutex);
pthread_mutex_trylock
非阻塞调用。当请求的锁正在被占用的时候, 不会进入阻塞状态,而是立刻返回,并返回一个错误代码 EBUSY,意思是说, 有其它线程正在使用这个锁。
直白点的说法,请求资源,能拿到就拿,拿不到我就继续往下执行。
函数原型:
int pthread_mutex_trylock(pthread_mutex_t *mutex);
pthread_mutex_unlock
释放互斥锁。
函数原型如下:
int pthread_mutex_unlock(pthread_mutex_t *mutex);
对于这些 API,如果成功,那么返回 0,否则返回错误码 errno
,可以通过下列宏定义打印错误信息:
#define handler_error_en(en, msg) \
do \
{ \
errno = en; \
perror(msg); \
exit(EXIT_FAILURE); \
} while (0)
例子:同步累加
对于「线程同步」一节给出的例子,使用互斥量实现同步操作,使得程序能够正确完成累加操作。
#include <stdlib.h>
#include <pthread.h>
#include <stdio.h>
#include <string.h>
const int N = 1e4;
int value = 0;
pthread_mutex_t mutex;
void *worker1(void *arg)
{
int i = 1;
int sum = 0;
for (; i <= N / 2; i++) sum += i;
// 这样保证 value 仅能由一个线程访问
pthread_mutex_lock(&mutex);
value += sum;
pthread_mutex_unlock(&mutex);
return NULL;
};
void *worker2(void *arg)
{
int i = N / 2 + 1;
int sum = 0;
for (; i <= N; i++) sum += i;
pthread_mutex_lock(&mutex);
value += sum;
pthread_mutex_unlock(&mutex);
return NULL;
}
int main()
{
pthread_t tid1, tid2;
pthread_mutex_init(&mutex, NULL);
pthread_create(&tid1, NULL, worker1, NULL);
pthread_create(&tid2, NULL, worker2, NULL);
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
printf("%d\n", value);
printf("SUM(1, %d) should be %d .\n", N, N * (N + 1) / 2);
pthread_mutex_destroy(&mutex);
}
pthread 互斥量的更多相关文章
- pthread中互斥量,锁和条件变量
互斥量 #include <pthread.h> pthread_mutex_t mutex=PTHREAD_MUTEX_INTIIALIZER; int pthread_mutex_in ...
- php Pthread 多线程 (三) Mutex 互斥量
当我们用多线程操作同一个资源时,在同一时间内只能有一个线程能够对资源进行操作,这时就需要用到互斥量了.比如我们对同一个文件进行读写操作时. <?php class Add extends Thr ...
- Linux/Unix 线程同步技术之互斥量(1)
众所周知,互斥量(mutex)是同步线程对共享资源访问的技术,用来防止下面这种情况:线程A试图访问某个共享资源时,线程B正在对其进行修改,从而造成资源状态不一致.与之相关的一个术语临界区(critic ...
- Linux 多线程互斥量互斥
同步 同一个进程中的多个线程共享所在进程的内存资源,当多个线程在同一时刻同时访问同一种共享资源时,需要相互协调,以避免出现数据的不一致和覆盖等问题,线程之间的协调和通信的就叫做线程的同步问题, 线程同 ...
- linux线程同步(1)-互斥量
一.概述 互斥量是线程同步的一种机制,用来保护多线程的共享资源.同一时刻,只允许一个线程对临界区进行 ...
- [转]一个简单的Linux多线程例子 带你洞悉互斥量 信号量 条件变量编程
一个简单的Linux多线程例子 带你洞悉互斥量 信号量 条件变量编程 希望此文能给初学多线程编程的朋友带来帮助,也希望牛人多多指出错误. 另外感谢以下链接的作者给予,给我的学习带来了很大帮助 http ...
- 共享内存+互斥量实现linux进程间通信 分类: Linux C/C++ 2015-03-26 17:14 67人阅读 评论(0) 收藏
一.共享内存简介 共享内存是进程间通信中高效方便的方式之一.共享内存允许两个或更多进程访问同一块内存,就如同 malloc() 函数向不同进程返回了指向同一个物理内存区域的指针,两个进程可以对一块共享 ...
- [linux basic 基础]----同步互斥量
互斥量,运行程序元锁住某个对象,使得每次只能有一个线程访问它:为了控制对关键代码的访问,必须在进入这段代码之前锁住一个互斥量,然后在完成操作之后解锁它 :基本函数与用于信号量的函数非常相似#inclu ...
- 【Linux】Mutex互斥量线程同步的例子
0.互斥量 Windows下的互斥量 是个内核对象,每次WaitForSingleObject和ReleaseMutex时都会检查当前线程ID和占有互斥量的线程ID是否一致. 当多次Wait**时就 ...
随机推荐
- c#分割习题
2.从一个记录了学生成绩的文本文档,每个学生成绩是一行,每行是用 | 分割的数据,用 | 分割的域分别是姓名.年龄.成绩.年级,写程序取出各个年级成绩最高学生的成绩.年级放到集合中.提示:(1)使用 ...
- lvs负载简介,原理,常见使用案例及Keepalived高可用
Lvs简介 基础概念 LVS(Linux Virtual Server)即Linux虚拟服务器,是由张文嵩博士主导的开源负载均衡项目,目前LVS已经被集成到Linux内核模块中(2.6及以上版本内核) ...
- 第05组 Alpha冲刺 (4/6)(组长)
.th1 { font-family: 黑体; font-size: 25px; color: rgba(0, 0, 255, 1) } #ka { margin-top: 50px } .aaa11 ...
- JavaScript一元运算符、二元运算符和三元运算符
在JavaScript中,运算符可以根据其实际操作数的个数进行分类. JavaScript中的大多数运算符是一个二元运算符(binary operator),将两个表达式合并成为一个稍复杂的表达式.譬 ...
- 是什么让我节省了60%的编码时间?使用MBG
MyBatis Generator简介 业务需求不断变更,数据库表结构不断修改,是我们逃不出的宿命.工欲善其事,必先利其器,是时候祭出神器了:MyBatis Generator(简称:MBG),它是一 ...
- 从ceph对象中提取RBD中的指定文件
前言 之前有个想法,是不是有办法找到rbd中的文件与对象的关系,想了很久但是一直觉得文件系统比较复杂,在fs 层的东西对ceph来说是透明的,并且对象大小是4M,而文件很小,可能在fs层进行了合并,应 ...
- debian修改crontab默认编辑器为vim
debian终端下默认编辑器为nano,比如crontab -e就会打开nano,这个编辑器用起来很不习惯,想修改为vim,当然,你的debian系统必须先安装vim.如果已经安装vim,请输入如下命 ...
- 前端JS下载文件总结
Data URLs Data URLs: 即前缀为data: 协议的URL,其允许内容创建者向文档中嵌入小文件. 例如:可以直接在HTML中的img元素直接使用Data URLs : data:[&l ...
- 贼厉害,手撸的 SpringBoot 缓存系统,性能杠杠的!
一.通用缓存接口 二.本地缓存 三.分布式缓存 四.缓存"及时"过期问题 五.二级缓存 缓存是最直接有效提升系统性能的手段之一.个人认为用好用对缓存是优秀程序员的必备基本素质. 本 ...
- mysql之sql语句逻辑执行顺序
1. (1)from先执行,from执行后就会将所有表(多个表时和单表所有的表)数据加载到内存中了 (2)ON执行,得到连接表用的连接条件. (3)JOIN执行,根据ON的连接条件,将from加载的所 ...