线程同步 - 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 ...
随机推荐
- Unity手机端手势基本操作
主要有单指移动3D物体.单指旋转3D物体.双指缩放3D物体. 基类 using UnityEngine; using System.Collections; /// <summary> / ...
- 【NS-3学习】ns3-模拟基础:关键概念,日志,命令行参数
前言 本篇博客先介绍在仿真过程中会使用到的一些关键概念,然后介绍便于调试仿真脚本的常用技术:日志.命令行参数. 关键概念 节点 在因特网术语中,主机(终端)是指任何一台连接到网络的计算设备.ns-3并 ...
- 如何在linux安装ruby2.2.2+
背景: 想搭建redis集群但是提示需要ruby2.2.2+ 直接使用yum安装 yum -y install ruby ruby-devel rubygems rpm-build 使用ruby -v ...
- Permission denied 解决办法
Permission denied 解决的办法: $ sudo chmod -R 777 某一目录 其中-R 是指级联应用到目录里的所有子目录和文件777 是所有用户都拥有最高权限
- [lua]紫猫lua教程-命令宝典-L1-01-06. 循环结构
L1[循环]01. for循环结构介绍 只是简单的说了下计数型的for循环结构 for i=1,10,1 do testlib.traceprint(i) end 注意几点: 1.上面的1和10表示循 ...
- Httpclient 工具类(get,put)
package com.googosoft.until; import java.io.IOException; import org.apache.http.HttpEntity; import o ...
- HttpServer性能比较
在自己的本子上随便测了下几款HttpServer,环境信息就不贴出来了,主要是比对下差距. 测试内容是输出 text/plain 的 hello, world. 先说结论:Netty > Joo ...
- java中Integer面试的坑
class Test{ public static void main(String[] args){ //当值在[-128,127]中,不创建新的Integer Integer f1 = 100,f ...
- 第10章-内部类II
Think in java 读书笔记 pikzas 2019.05.05 第十章 内部类 知识点 1.什么是内部类 可以将一个类定义在另一个类的内部 class OuterClass{ class I ...
- php相关问题学习(以备面试)
1.原味地址:[ http://www.yiichina.com/tutorial/57 ] 注:本文转自 http://www.icultivator.com/p/5535.html 整理了一份PH ...