▶ 一个简单的 Pthreads 程序(不按照《并行程序设计导论》中的程序来写)

● 代码

 #include <stdio.h>
#include <pthread.h>
#pragma comment(lib, "pthreadVC2.lib") const int thread = ; void* work(void* input)
{
if (input == nullptr)
printf("nullptr!\n");
else
printf("%d\n", *((int *)input)); // 将得到的 void * 参数转化为需要的数据类型再进行使用
return nullptr;
} int main()
{
pthread_t array[thread]; // 产生各线程的 pthread_t 对象
int i, list[thread]; for (i = ; i < thread; i++)
{
list[i] = i * ;
pthread_create(&array[i], nullptr, work, &list[i]); // 生成各线程来运行函数 work(),函数参数为 list[i],没有线程属性参数
}
for (i = ; i < thread; i++)
pthread_join(array[i], nullptr); // 终止各线程
getchar();
return ;
}

● 输出结果:8 个乱序的数字


● 用到的定义,pthread.h

 typedef struct
{
void * p; // Pointer to actual object
unsigned int x; // Extra information - reuse count etc
} ptw32_handle_t; typedef ptw32_handle_t pthread_t;
typedef struct pthread_attr_t_ * pthread_attr_t;// 没有其他地方提到了 struct pthread_attr_t_ 的成员 PTW32_DLLPORT int PTW32_CDECL pthread_create(
pthread_t * tid, // 输入 pthread_t 的指针
const pthread_attr_t * attr, // pthread_t 对象的属性
void *(PTW32_CDECL *start) (void *), // 工作函数,输入参数和返回类型均为 void *
void *arg // 工作函数的输入参数
); PTW32_DLLPORT int PTW32_CDECL pthread_join(
pthread_t thread, // 需要等待终止的 pthread_t 对象,注意不是指针
void **value_ptr // ?
);

▶ 使用直接访问、忙等待和互斥量计算 π 的值,使用公式 π / 4 = 1 - 1 / 3 + 1 / 5 - 1 / 7 + ...,Mathematica 的精确结果为 0.78539816339744830962

● 直接访问临界区,代码

 #include <stdio.h>
#include <pthread.h>
#include <time.h>
#pragma comment(lib, "pthreadVC2.lib") const int count = , thread = ;// 使用 8 个线程来计算 2^30 项
double sum; void* threadSum_naïve(void* rank)
{
const long long localRank = (long long)rank;// 使用 long long 类型,可以直接与 void* 相互转化
const int localCount = count / thread;
int i;
double sign;
if (localCount * localRank % )
sign = -1.0;
else
sign = 1.0;
for (i = localCount*localRank; i < localCount*(localRank + ); i++, sign = -sign)
sum += sign / ( * i + );
printf("Thread %2d finished.\n", localRank);
return nullptr;
} int main()
{
pthread_t array[thread];
int i;
long long list[thread];
clock_t time = clock();
for (i = , sum = 0.0; i < thread; i++)
{
list[i] = i;
pthread_create(&array[i], nullptr, threadSum_naïve, (void *)list[i]);
}
for (i = ; i < thread; i++)
pthread_join(array[i], nullptr);
time = clock() - time;
printf("\nsum = %2.10f, time = %d ms\n", sum, time);
getchar();
return ;
}

● 输出结果,发现与精确结果相差很大,这是由于读写冲突造成的

Thread   finished.
Thread finished.
Thread finished.
Thread finished.
Thread finished.
Thread finished.
Thread finished.
Thread finished. sum = 0.7852892761, time = ms

● 忙等待法,代码

 #include <stdio.h>
#include <pthread.h>
#include <time.h>
#pragma comment(lib, "pthreadVC2.lib") const int count = , thread = ;
double sum;
int flag; void* threadSum(void* rank)
{
const long long localRank = (long long)rank;
const int localCount = count / thread;
int i;
double sign;
if (localCount * localRank % )
sign = -1.0;
else
sign = 1.0;
for (i = localCount*localRank; i < localCount*(localRank + ); i++, sign = -sign)
{
while (flag != localRank); // 等待读写标志等于线程编号时进行写入
sum += sign / ( * i + );
flag = (flag + ) % thread;// 写入完成调整读写标志以便下一个线程写入
}
printf("Thread %2d finished.\n", localRank);
return nullptr;
} int main()
{
pthread_t array[thread];
int i;
long long list[thread];
clock_t time = clock();
flag = ;
for (i = , sum = 0.0; i < thread; i++)
{
list[i] = i;
pthread_create(&array[i], nullptr, threadSum, (void *)list[i]);
}
for (i = ; i < thread; i++)
pthread_join(array[i], nullptr);
time = clock() - time;
printf("\nsum = %2.10f, time = %d ms\n", sum, time);
getchar();
return ;
}

● 输出结果,发现花费的时间非常长,这是因为每个线程每次向结果中写入一个数,造成了极长的等待队列

Thread   finished.
Thread finished.
Thread finished.
Thread finished.
Thread finished.
Thread finished.
Thread finished.
Thread finished. sum = 0.7853981632, time = ms

● 忙等待法 + 局部和,代码

 #include <stdio.h>
#include <pthread.h>
#include <time.h>
#pragma comment(lib, "pthreadVC2.lib") const int count = , thread = ;
double sum;
int flag; void* threadSum(void* rank)
{
const long long localRank = (long long)rank;
const int localCount = count / thread;
int i;
double sign, localSum;
if (localCount * localRank % )
sign = -1.0;
else
sign = 1.0;
for (i = localCount * localRank, localSum = 0.0; i < localCount * (localRank + ); localSum += sign / ( * i + ), i++, sign = -sign);
for (; flag != localRank;);// 仍然使用忙等待,但是每个线程仅向总和中写入一次部分和
sum += localSum;
flag = (flag + ) % thread; printf("Thread %2d finished.\n", localRank);
return nullptr;
} int main()
{
pthread_t array[thread];
int i;
long long list[thread];
clock_t time = clock();
flag = ;
for (i = , sum = 0.0; i < thread; i++)
{
list[i] = i;
pthread_create(&array[i], nullptr, threadSum, (void *)list[i]);
}
for (i = ; i < thread; i++)
pthread_join(array[i], nullptr);
time = clock() - time;
printf("\nsum = %2.10f, time = %d ms\n", sum, time);
getchar();
return ;
}

● 输出结果,速度大为加快

Thread   finished.
Thread finished.
Thread finished.
Thread finished.
Thread finished.
Thread finished.
Thread finished.
Thread finished. sum = 0.7853981632, time = ms

● 使用互斥量,代码

 #include <stdio.h>
#include <pthread.h>
#include <time.h>
#pragma comment(lib, "pthreadVC2.lib") const int count = , thread = ;
double sum;
pthread_mutex_t pmt; void* threadSum(void* rank)
{
const long long localRank = (long long)rank;
const int localCount = count / thread;
int i;
double sign, localSum;
if (localCount * localRank % )
sign = -1.0;
else
sign = 1.0;
for (i = localCount * localRank, localSum = 0.0; i < localCount * (localRank + ); localSum += sign / ( * i + ), i++, sign = -sign);
pthread_mutex_lock(&pmt); // 与使用忙等待相同的办法使用互斥量
sum += localSum;
pthread_mutex_unlock(&pmt); printf("Thread %2d finished.\n", localRank);
return nullptr;
} int main()
{
pthread_t array[thread];
int i;
long long list[thread];
clock_t time = clock();
pthread_mutex_init(&pmt, nullptr);// 初始化互斥量
for (i = , sum = 0.0; i < thread; i++)
{
list[i] = i;
pthread_create(&array[i], nullptr, threadSum, (void *)list[i]);
}
for (i = ; i < thread; i++)
pthread_join(array[i], nullptr);
pthread_mutex_destroy(&pmt); // 销毁互斥量
time = clock() - time;
printf("\nsum = %2.10f, time = %d ms\n", sum, time);
getchar();
return ;
}

● 输出结果,速度与使用忙等待相近

Thread   finished.
Thread finished.
Thread finished.
Thread finished.
Thread finished.
Thread finished.
Thread finished.
Thread finished. sum = 0.7853981632, time = ms

● 用到的定义,pthread.h

 typedef struct pthread_mutex_t_ * pthread_mutex_t;
typedef struct pthread_mutexattr_t_ * pthread_mutexattr_t; PTW32_DLLPORT int PTW32_CDECL pthread_mutex_init(pthread_mutex_t * mutex, const pthread_mutexattr_t * attr);
// 初始化互斥量,输入已经声明的一个 pthread_mutex_t 变量的指针及一个 pthread_mutexattr_t 属性指针,初始化完成后互斥量为解锁状态 PTW32_DLLPORT int PTW32_CDECL pthread_mutex_destroy(pthread_mutex_t * mutex); // 销毁用完的互斥量 PTW32_DLLPORT int PTW32_CDECL pthread_mutex_lock(pthread_mutex_t * mutex); // 锁定互斥量以访问临界区 PTW32_DLLPORT int PTW32_CDECL pthread_mutex_unlock(pthread_mutex_t * mutex); // 解锁互斥量以离开临界区访问

Pthreads Hello World,忙等待,互斥量的更多相关文章

  1. 【转】【Linux】 临界区,互斥量,信号量,事件的区别

    原文地址:http://blog.itpub.net/10697500/viewspace-612045/ Linux中 四种进程或线程同步互斥的控制方法1.临界区:通过对多线程的串行化来访问公共资源 ...

  2. 经典线程同步 互斥量Mutex

    阅读本篇之前推荐阅读以下姊妹篇: <秒杀多线程第四篇一个经典的多线程同步问题> <秒杀多线程第五篇经典线程同步关键段CS> <秒杀多线程第六篇经典线程同步事件Event& ...

  3. Linux的线程同步对象:互斥量Mutex,读写锁,条件变量

        进程是Linux资源分配的对象,Linux会为进程分配虚拟内存(4G)和文件句柄等 资源,是一个静态的概念.线程是CPU调度的对象,是一个动态的概念.一个进程之中至少包含有一个或者多个线程.这 ...

  4. [一个经典的多线程同步问题]解决方案三:互斥量Mutex

    本篇通过互斥量来解决线程的同步,学习其中的一些知识. 互斥量也是一个内核对象,它用来确保一个线程独占一个资源的访问.互斥量与关键段的行为非常相似,并且互斥量可以用于不同进程中的线程互斥访问资源.使用互 ...

  5. (转)经典线程同步 互斥量Mutex

    阅读本篇之前推荐阅读以下姊妹篇: <秒杀多线程第四篇一个经典的多线程同步问题> <秒杀多线程第五篇经典线程同步关键段CS> <秒杀多线程第六篇经典线程同步事件Event& ...

  6. 多线程面试题系列(7):经典线程同步 互斥量Mutex

    前面介绍了关键段CS.事件Event在经典线程同步问题中的使用.本篇介绍用互斥量Mutex来解决这个问题. 互斥量也是一个内核对象,它用来确保一个线程独占一个资源的访问.互斥量与关键段的行为非常相似, ...

  7. windows多线程同步--互斥量

    关于互斥量的基本概念:百度百科互斥量 推荐参考博客:秒杀多线程第七篇 经典线程同步 互斥量Mutex 注意:互斥量也是一个内核对象,它用来确保一个线程独占一个资源的访问.互斥量与关键段的行为非常相似, ...

  8. 秒杀多线程第七篇 经典线程同步 互斥量Mutex

    本文转载于:http://blog.csdn.net/morewindows/article/details/7470936 前面介绍了关键段CS.事件Event在经典线程同步问题中的使用.本篇介绍用 ...

  9. windows多线程(六) 互斥量Mutex与关键段CriticalSection比较

    一.关键段CS 和 互斥量Mutex 的相同点:都有线程拥有权 关键段和互斥量都有线程拥有权,即可以被一个线程拥有.在 前面讲关键段CS的文章中有说到,关键段结构体的第四个参数保存着拥有该关键段的线程 ...

  10. windows多线程(五) 互斥量 Mutex

    一.互斥量 互斥量是windows的一个内核对象,互斥量与关键段的作用相似,可以用来确保全局资源的互斥访问.并且互斥量可以用在不同的进程中的线程互斥访问全局资源. 二.相关函数说明 使用互斥量Mute ...

随机推荐

  1. Rails-treasure chest4: 使用图表对资料进行分析chart.js(及其他);管理用户权限的gem 'Pumdit'(6000🌟)

    * 多档案上传* 图表资料分析  Chartkick gem或者 chart.js* 用户权限控管  gem Pundit (6000✨) *HTML E-mail 寄送 : gem premaile ...

  2. (GoRails)ActionCable如何用Redis + 菜鸟redis教程

    视频: https://gorails.com/episodes/how-actioncable-uses-redis?autoplay=1 原理PubSub, 你进入一个频道,然后就能接收,和发布信 ...

  3. Rails 5 Test Prescriptions 第14章 Testing Exteranl Services(中断。)

    external testing strategy ✅ the service integration test✅ introduce VCR✅ Client Unit Tests ❌ Why an ...

  4. CSS cursor 和 opacity 属性

    cursor :一些不同的光标,当设置该属性之后,鼠标指上去会随着属性而改变. 举例: <span style="cursor:crosshair">十字线</s ...

  5. 将 Spring boot 项目打成可执行Jar包,及相关注意事项(main-class、缺少 xsd、重复打包依赖)

    最近在看 spring boot 的东西,觉得很方便,很好用.对于一个简单的REST服务,都不要自己部署Tomcat了,直接在 IDE 里 run 一个包含 main 函数的主类就可以了. 但是,转念 ...

  6. vue-router与v-if实现tab切换的思考

    vue-router 该如何使用 忽然碰到一个常见的问题,明明可以使用 v-if / v-show 可以的解决的问题,有没有必要是使用 vue-router来解决. 比如常见的 tab 切换.一时间, ...

  7. CORS请求

    一.简介 CORS(跨域资源共享 Cross-origin resource sharing)是实现跨域的一种常用方式.实现CORS通信的关键是服务器.只要服务器实现了CORS接口,就可以跨源通信 二 ...

  8. Java web.xml 配置技巧—动态欢迎页地址

    我们的 Java   Web  项目在配置web.xml 欢迎页地址默认是index.html .index.jsp ,不知道有人注意过没有,如果我要配置成/index/user.action  或者 ...

  9. Jenkins插件开发(二)-- HelloWorld

    在上一篇blog中我们讲了如何搭建jenkins插件的开发环境,接下来介绍如何开发我们的插件. 创建HelloWorld插件 学习每门新语言的时候,我们都会写一个HelloWorld程序,这里介绍的是 ...

  10. 发现TypeScript中同名interface接口会自动合并的特性

    今天在学习怎么用TypeScript给jQuery写扩展插件时发现一个很有趣的事情