线程同步 - POSIX互斥锁
线程同步 - POSIX互斥锁
概括
本文讲解POSIX中互斥量的基本用法,从而能达到简单的线程同步。互斥量
是一种特殊的变量,它有两种状态:锁定以及解锁。如果互斥量是锁定的,就有一个特定的线程持有或者拥有这个互斥量;如果没有线程持有这个互斥量,我们就说这个互斥量是解锁的、可用的。同时,互斥量还有一个等待持有该互斥量的线程队列。互斥队列中的线程获得互斥量的顺序由线程调度所决定,但POSIX没有要求实现任何特定的策略。
程序描述
现在我们尝试写一个程序来体会互斥量的基本应用,用程序来模拟验证:$$\int_0^1sinx dx = 1.0 - cos1 $$ 利用多个子线程来产生[0,1]之间的随机数,每产生一次count
则增加一,并且将产生的数加入sum
,然后用sum/count
来模拟等式左边,最后计算等式右边作为标准值,然后计算误差。
程序用法:从命令行参数中接受要创建的线程数目以及运行时间,即$ ./程序名 线程数 等待时间
。
全局变量设计:
static int doneflag = 0;
static int count = 0;
static double sum = 0;
static pthread_mutex_t flaglock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t sumlock = PTHREAD_MUTEX_INITIALIZER;
用sumlock
来守护count
和sum
,用flaglock
来守护doneflag
。
main
函数里创建线程数组,然后用pthread_create
来创建线程,用pthread_join
来等待线程。关键语句:
num_threads = atoi(argv[1]);
tids = (pthread_t *)calloc(num_threads, sizeof(pthread_t);
for (i = 0; i < num_threads; ++i) /* 创建num_threads个compute_thread线程 */
pthread_create(tids + i, NULL, compute_thread, NULL);
线程函数
注意创建的线程处理函数的形式:void *(*start_routine) (void *)
, 将函数指针(函数名)传递给pthread_create
即可。子进程循环计算,直到doneflag == 1
。
其它函数
randsafe()
:用一个互斥量来保护rand()
,要确保不会有两个线程同时调用rand,因为它在多线程中是不安全的。其次,rand不是一个特别好的伪随机数生成器,所以应该在实际程序中避免使用它,这里只是用作demo示范。
set_done
和get_done
分别用于设置flag和获得flag。
最后show_results
来整理数据并进行输出。
运行情况
$ gcc -o demo mutex_demo.c -lm -lpthread
$ ./demo 5 1
The sum is 232.913662 and the count is 500
The average is 0.465827 and error is 0.006130 or 1.333405%
$ ./demo 10 1
The sum is 467.382538 and the count is 1000
The average is 0.467383 and error is 0.007685 or 1.671717%
$ ./demo 10 2
The sum is 919.177364 and the count is 1990
The average is 0.461898 and error is 0.002200 or 0.478680%
源代码
/**
* @Description: 利用子线程计算0-1范围内正弦函数的平均值,并与实际值进行误差比较。
*/
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <time.h>
#include <unistd.h>
#define TEM_MILLION 10000000L
static int doneflag = 0;
static int count = 0;
static double sum = 0;
static pthread_mutex_t flaglock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t sumlock = PTHREAD_MUTEX_INITIALIZER;
/* 线程函数, 计算随机和 */
void *compute_thread(void *arg1);
int set_done(void);
int get_done(int *flag);
int randsafe(double *valp);
int add(double x);
int show_results(void);
int main(int argc, char *argv[])
{
int i;
int num_threads;
int sleep_time;
pthread_t *tids;
if (argc != 3) {
fprintf(stderr, "Usage: %s num_threads sleep_time\n", argv[0]);
return 1;
}
num_threads = atoi(argv[1]);
sleep_time = atoi(argv[2]);
if ((tids = (pthread_t *)calloc(num_threads, sizeof(pthread_t))) == NULL) {
perror("Failed to allocate space for thread IDs");
return 1;
}
for (i = 0; i < num_threads; ++i) /* 创建num_threads个compute_thread线程 */
pthread_create(tids + i, NULL, compute_thread, NULL);
sleep(sleep_time);
set_done();
for (i = 0; i < num_threads; ++i) /* 等待线程完成 */
pthread_join(tids[i], NULL);
if (show_results())
return 1;
return 0;
}
/* 线程函数, 计算随机和 */
void *compute_thread(void *arg1) {
int localdone = 0;
struct timespec sleep_local;
double val;
sleep_local.tv_sec = 0;
sleep_local.tv_nsec = TEM_MILLION; /* 10ms */
while (!localdone) {
randsafe(&val);
add(sin(val));
get_done(&localdone);
nanosleep(&sleep_local, NULL); /* 让其他线程进入 */
}
}
int set_done(void) {
pthread_mutex_lock(&flaglock);
doneflag = 1;
return pthread_mutex_unlock(&flaglock);
}
int get_done(int *flag) {
pthread_mutex_lock(&flaglock);
*flag = doneflag;
return pthread_mutex_unlock(&flaglock);
}
int randsafe(double *valp) {
static pthread_mutex_t randlock = PTHREAD_MUTEX_INITIALIZER;
*valp = (double)rand() / (double)RAND_MAX;
return pthread_mutex_unlock(&randlock);
}
int add(double x) {
pthread_mutex_lock(&sumlock);
sum += x;
count++;
return pthread_mutex_unlock(&sumlock);
}
int show_results(void) {
int res_count;
double res_sum;
double calculated;
double average;
double err;
double perr;
pthread_mutex_lock(&sumlock);
res_sum = sum;
res_count = count;
pthread_mutex_unlock(&sumlock);
if (count == 0)
printf("No values were summed.\n");
else {
calculated = 1.0 - cos(1.0);
average = sum/count;
err = average - calculated;
perr = 100.0*err/calculated;
printf("The sum is %f and the count is %d\n", sum, count);
printf("The average is %f and error is %f or %f%%\n", average, err, perr);
}
return 0;
}
线程同步 - POSIX互斥锁的更多相关文章
- APUE学习笔记——11 线程同步、互斥锁、自旋锁、条件变量
线程同步 同属于一个进程的不同线程是共享内存的,因而在执行过程中需要考虑数据的一致性. 假设:进程有一变量i=0,线程A执行i++,线程B执行i++,那么最终i的取值是多少呢?似乎一定 ...
- UNIX环境高级编程——线程同步之互斥锁、读写锁和条件变量(小结)
一.使用互斥锁 1.初始化互斥量 pthread_mutex_t mutex =PTHREAD_MUTEX_INITIALIZER;//静态初始化互斥量 int pthread_mutex_init( ...
- ReactiveSwift源码解析(十一) Atomic的代码实现以及其中的Defer延迟、Posix互斥锁、递归锁
本篇博客我们来聊一下ReactiveSwift中的原子性操作,在此内容上我们简单的聊一下Posix互斥锁以及递归锁的概念以及使用场景.然后再聊一下Atomic的代码实现.Atomic主要负责多线程下的 ...
- Python进阶----线程基础,开启线程的方式(类和函数),线程VS进程,线程的方法,守护线程,详解互斥锁,递归锁,信号量
Python进阶----线程基础,开启线程的方式(类和函数),线程VS进程,线程的方法,守护线程,详解互斥锁,递归锁,信号量 一丶线程的理论知识 什么是线程: 1.线程是一堆指令,是操作系统调度 ...
- win32进阶必备:多线程同步之互斥锁
应用多线程互斥锁之前首先简单过一下C程序可能用到的3个创建线程函数: CreateThread,windows系统提供的唯一创建线程API,_beginthread和_beginthreadex都在内 ...
- UNIX环境高级编程——线程同步之互斥量
互斥量(也称为互斥锁)出自POSIX线程标准,可以用来同步同一进程中的各个线程.当然如果一个互斥量存放在多个进程共享的某个内存区中,那么还可以通过互斥量来进行进程间的同步. 互斥量,从字面上就可以知道 ...
- linux线程同步(1)-互斥量
一.概述 互斥量是线程同步的一种机制,用来保护多线程的共享资源.同一时刻,只允许一个线程对临界区进行 ...
- exec函数族,守护进程,线程同步和互斥
2015.3.2 进程和程序有三点不同:1,存在位置不同,程序:硬盘,磁盘.进程:内存2. 程序是静态的,进程是动态的 执行./a.out -->bash->bash程序调用fork()- ...
- node源码详解(七) —— 文件异步io、线程池【互斥锁、条件变量、管道、事件对象】
本作品采用知识共享署名 4.0 国际许可协议进行许可.转载保留声明头部与原文链接https://luzeshu.com/blog/nodesource7 本博客同步在https://cnodejs.o ...
随机推荐
- OSI七层协议详解
一.简介 开放系统互连参考模型 (Open System Interconnect 简称OSI)是国际标准化组织(ISO)和国际电报电话咨询委员会(CCITT)联合制定的开放系统互连参考模型,为开放式 ...
- tomcat8.5优化配置
参考文章: https://www.cnblogs.com/steven-snow/p/9262025.html 1.Tomcat内存使用调整 windows系统在bin/catalina.bat文件 ...
- 全网最详细!搭建Hexo+Coding/Gitee,实现一键生成,同步部署
全网最全小白搭建Hexo+Gitee/Coding/Github 全网最全小白搭建Hexo+Gitee/Coding/Github 本站内容已全部转移到https://www.myyuns.ltd,具 ...
- 剑指offer 面试题35.复杂链表的复制
时间O(N),空间O(N) /* struct RandomListNode { int label; struct RandomListNode *next, *random; RandomList ...
- 如何预测股票分析--先知(Prophet)
在上一篇中,我们探讨了自动ARIMA,但是好像表现的还是不够完善,接下来看看先知的力量! 先知(Prophet) 有许多时间序列技术可以用在股票预测数据集上,但是大多数技术在拟合模型之前需要大量的数据 ...
- AcWing 859. Kruskal算法求最小生成树 稠密图
//稠密图 #include <cstring> #include <iostream> #include <algorithm> using namespace ...
- 欧拉降幂 (a^t)%c 模板
#include<bits/stdc++.h> using namespace std; typedef long long ll; ll a,c,p,mod; ]; ll phi(ll ...
- React的React.createElement源码解析(一)
一.什么是jsx jsx是语法糖 它是js和html的组合使用 二.为什么用jsx语法 高效定义模版,编译后使用 不会带来性能问题 三.jsx语法转化为js语法 jsx语法通过babel转化为 ...
- RLE压缩算法详解
from:http://data.biancheng.net/view/152.html RLE压缩算法(下简称RLE算法)的基本思路是把数据按照线性序列分成两种情况:一种是连续的重复数据块,另一种是 ...
- Sublime Text3搭建完美开发环境(Python+PHP+Javascript+nodejs+C++)
一.Sublime配置(如已安装Package Control可跳过) sublime下载地址:http://www.sublimetext.com/3 安装Package Control插件: 直接 ...