▶ 一个简单的 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. python学习笔记(断言assert)

    最近有了些时间 博主一直在python的unittest框架,这次想看看其他框架 先准备熟悉熟悉 pytest,由于unittest有自己断言方法 而pytest则是使用python自带的 asser ...

  2. SpringInAction--SpringMvc高级技术(servlet、filter、multipart)

    前面学了spirng的一些配置,以及web方面的知识,今天就在学习一下在spring比较常用的一些高级技术... 首先来介绍下什么叫servlet吧(来着维基百科) Servlet(Server Ap ...

  3. Android EditText 中hint文字大小以及与输入文字颜色保存一致

    SpannableString 这个就是用来处理android 文本信息 可编辑 可点击 感兴趣的自己去看! /* * Copyright (C) 2006 The Android Open Sour ...

  4. boost 中文编码转换

    Lstring CHanderHttp::CircleDesc(Lint nCurCircle, Lint nMaxCircle,Lint usercount){ std::stringstream ...

  5. 1月中旬值得一读的10本技术新书(机器学习、Java、大数据等)!

    1月中旬,阿里云云栖社区 联合 博文视点 为大家带来十本技术书籍(机器学习.Java.大数据等).以下为书籍详情,文末还有福利哦! 书籍名称:Oracle数据库问题解决方案和故障排除手册 内容简介 & ...

  6. Jmeter-Transaction Controller(事务控制器)

    generate parent sample:生成父样本 include duration of timer and pre-post processors in generated sample:在 ...

  7. Hadoop_10_shuffle01_Hadoop中的Shuffle详解【来源网络】

    原文网址:http://blog.itpub.net/30316686/viewspace-2057204/ 详细的了解Shuffle过程,能更好的对hadoop集群进行优化.         Map ...

  8. java面试题7

    1.重载和重写的区别? 重载(Overload):(1)方法重载是让类以统一的方式处理不同类型数据的一种手段.多个同名函数同时存在,具有不同的参数个数/类型.重载Overloading是一个类中多态性 ...

  9. 将 UWP 中 CommandBar 的展开方向改为向下展开

    在 UWP 中使用 CommandBar 来迅速添加一组功能按钮是非常迅速的,是 UWP 中推荐的交互方案之一.也许你能见到 CommandBar 按你所需向下展开,不过可能更多数情况会看到 Comm ...

  10. 2018-2019-1 20165212 《信息安全系统设计基础》第八周学习总结(pwd)

    2018-2019-1 20165212 <信息安全系统设计基础>第八周学习总结 一.知识点总结 1.三种并发方式 构造并发程序的方法有三种: 进程 线程 I/O多路复用 进程:用内核来调 ...