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

● 代码

  1. #include <stdio.h>
  2. #include <pthread.h>
  3. #pragma comment(lib, "pthreadVC2.lib")
  4.  
  5. const int thread = ;
  6.  
  7. void* work(void* input)
  8. {
  9. if (input == nullptr)
  10. printf("nullptr!\n");
  11. else
  12. printf("%d\n", *((int *)input)); // 将得到的 void * 参数转化为需要的数据类型再进行使用
  13. return nullptr;
  14. }
  15.  
  16. int main()
  17. {
  18. pthread_t array[thread]; // 产生各线程的 pthread_t 对象
  19. int i, list[thread];
  20.  
  21. for (i = ; i < thread; i++)
  22. {
  23. list[i] = i * ;
  24. pthread_create(&array[i], nullptr, work, &list[i]); // 生成各线程来运行函数 work(),函数参数为 list[i],没有线程属性参数
  25. }
  26. for (i = ; i < thread; i++)
  27. pthread_join(array[i], nullptr); // 终止各线程
  28. getchar();
  29. return ;
  30. }

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

  1.  

● 用到的定义,pthread.h

  1. typedef struct
  2. {
  3. void * p; // Pointer to actual object
  4. unsigned int x; // Extra information - reuse count etc
  5. } ptw32_handle_t;
  6.  
  7. typedef ptw32_handle_t pthread_t;
  8. typedef struct pthread_attr_t_ * pthread_attr_t;// 没有其他地方提到了 struct pthread_attr_t_ 的成员
  9.  
  10. PTW32_DLLPORT int PTW32_CDECL pthread_create(
  11. pthread_t * tid, // 输入 pthread_t 的指针
  12. const pthread_attr_t * attr, // pthread_t 对象的属性
  13. void *(PTW32_CDECL *start) (void *), // 工作函数,输入参数和返回类型均为 void *
  14. void *arg // 工作函数的输入参数
  15. );
  16.  
  17. PTW32_DLLPORT int PTW32_CDECL pthread_join(
  18. pthread_t thread, // 需要等待终止的 pthread_t 对象,注意不是指针
  19. void **value_ptr // ?
  20. );

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

● 直接访问临界区,代码

  1. #include <stdio.h>
  2. #include <pthread.h>
  3. #include <time.h>
  4. #pragma comment(lib, "pthreadVC2.lib")
  5.  
  6. const int count = , thread = ;// 使用 8 个线程来计算 2^30 项
  7. double sum;
  8.  
  9. void* threadSum_naïve(void* rank)
  10. {
  11. const long long localRank = (long long)rank;// 使用 long long 类型,可以直接与 void* 相互转化
  12. const int localCount = count / thread;
  13. int i;
  14. double sign;
  15. if (localCount * localRank % )
  16. sign = -1.0;
  17. else
  18. sign = 1.0;
  19. for (i = localCount*localRank; i < localCount*(localRank + ); i++, sign = -sign)
  20. sum += sign / ( * i + );
  21. printf("Thread %2d finished.\n", localRank);
  22. return nullptr;
  23. }
  24.  
  25. int main()
  26. {
  27. pthread_t array[thread];
  28. int i;
  29. long long list[thread];
  30. clock_t time = clock();
  31. for (i = , sum = 0.0; i < thread; i++)
  32. {
  33. list[i] = i;
  34. pthread_create(&array[i], nullptr, threadSum_naïve, (void *)list[i]);
  35. }
  36. for (i = ; i < thread; i++)
  37. pthread_join(array[i], nullptr);
  38. time = clock() - time;
  39. printf("\nsum = %2.10f, time = %d ms\n", sum, time);
  40. getchar();
  41. return ;
  42. }

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

  1. Thread finished.
  2. Thread finished.
  3. Thread finished.
  4. Thread finished.
  5. Thread finished.
  6. Thread finished.
  7. Thread finished.
  8. Thread finished.
  9.  
  10. sum = 0.7852892761, time = ms

● 忙等待法,代码

  1. #include <stdio.h>
  2. #include <pthread.h>
  3. #include <time.h>
  4. #pragma comment(lib, "pthreadVC2.lib")
  5.  
  6. const int count = , thread = ;
  7. double sum;
  8. int flag;
  9.  
  10. void* threadSum(void* rank)
  11. {
  12. const long long localRank = (long long)rank;
  13. const int localCount = count / thread;
  14. int i;
  15. double sign;
  16. if (localCount * localRank % )
  17. sign = -1.0;
  18. else
  19. sign = 1.0;
  20. for (i = localCount*localRank; i < localCount*(localRank + ); i++, sign = -sign)
  21. {
  22. while (flag != localRank); // 等待读写标志等于线程编号时进行写入
  23. sum += sign / ( * i + );
  24. flag = (flag + ) % thread;// 写入完成调整读写标志以便下一个线程写入
  25. }
  26. printf("Thread %2d finished.\n", localRank);
  27. return nullptr;
  28. }
  29.  
  30. int main()
  31. {
  32. pthread_t array[thread];
  33. int i;
  34. long long list[thread];
  35. clock_t time = clock();
  36. flag = ;
  37. for (i = , sum = 0.0; i < thread; i++)
  38. {
  39. list[i] = i;
  40. pthread_create(&array[i], nullptr, threadSum, (void *)list[i]);
  41. }
  42. for (i = ; i < thread; i++)
  43. pthread_join(array[i], nullptr);
  44. time = clock() - time;
  45. printf("\nsum = %2.10f, time = %d ms\n", sum, time);
  46. getchar();
  47. return ;
  48. }

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

  1. Thread finished.
  2. Thread finished.
  3. Thread finished.
  4. Thread finished.
  5. Thread finished.
  6. Thread finished.
  7. Thread finished.
  8. Thread finished.
  9.  
  10. sum = 0.7853981632, time = ms

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

  1. #include <stdio.h>
  2. #include <pthread.h>
  3. #include <time.h>
  4. #pragma comment(lib, "pthreadVC2.lib")
  5.  
  6. const int count = , thread = ;
  7. double sum;
  8. int flag;
  9.  
  10. void* threadSum(void* rank)
  11. {
  12. const long long localRank = (long long)rank;
  13. const int localCount = count / thread;
  14. int i;
  15. double sign, localSum;
  16. if (localCount * localRank % )
  17. sign = -1.0;
  18. else
  19. sign = 1.0;
  20. for (i = localCount * localRank, localSum = 0.0; i < localCount * (localRank + ); localSum += sign / ( * i + ), i++, sign = -sign);
  21. for (; flag != localRank;);// 仍然使用忙等待,但是每个线程仅向总和中写入一次部分和
  22. sum += localSum;
  23. flag = (flag + ) % thread;
  24.  
  25. printf("Thread %2d finished.\n", localRank);
  26. return nullptr;
  27. }
  28.  
  29. int main()
  30. {
  31. pthread_t array[thread];
  32. int i;
  33. long long list[thread];
  34. clock_t time = clock();
  35. flag = ;
  36. for (i = , sum = 0.0; i < thread; i++)
  37. {
  38. list[i] = i;
  39. pthread_create(&array[i], nullptr, threadSum, (void *)list[i]);
  40. }
  41. for (i = ; i < thread; i++)
  42. pthread_join(array[i], nullptr);
  43. time = clock() - time;
  44. printf("\nsum = %2.10f, time = %d ms\n", sum, time);
  45. getchar();
  46. return ;
  47. }

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

  1. Thread finished.
  2. Thread finished.
  3. Thread finished.
  4. Thread finished.
  5. Thread finished.
  6. Thread finished.
  7. Thread finished.
  8. Thread finished.
  9.  
  10. sum = 0.7853981632, time = ms

● 使用互斥量,代码

  1. #include <stdio.h>
  2. #include <pthread.h>
  3. #include <time.h>
  4. #pragma comment(lib, "pthreadVC2.lib")
  5.  
  6. const int count = , thread = ;
  7. double sum;
  8. pthread_mutex_t pmt;
  9.  
  10. void* threadSum(void* rank)
  11. {
  12. const long long localRank = (long long)rank;
  13. const int localCount = count / thread;
  14. int i;
  15. double sign, localSum;
  16. if (localCount * localRank % )
  17. sign = -1.0;
  18. else
  19. sign = 1.0;
  20. for (i = localCount * localRank, localSum = 0.0; i < localCount * (localRank + ); localSum += sign / ( * i + ), i++, sign = -sign);
  21. pthread_mutex_lock(&pmt); // 与使用忙等待相同的办法使用互斥量
  22. sum += localSum;
  23. pthread_mutex_unlock(&pmt);
  24.  
  25. printf("Thread %2d finished.\n", localRank);
  26. return nullptr;
  27. }
  28.  
  29. int main()
  30. {
  31. pthread_t array[thread];
  32. int i;
  33. long long list[thread];
  34. clock_t time = clock();
  35. pthread_mutex_init(&pmt, nullptr);// 初始化互斥量
  36. for (i = , sum = 0.0; i < thread; i++)
  37. {
  38. list[i] = i;
  39. pthread_create(&array[i], nullptr, threadSum, (void *)list[i]);
  40. }
  41. for (i = ; i < thread; i++)
  42. pthread_join(array[i], nullptr);
  43. pthread_mutex_destroy(&pmt); // 销毁互斥量
  44. time = clock() - time;
  45. printf("\nsum = %2.10f, time = %d ms\n", sum, time);
  46. getchar();
  47. return ;
  48. }

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

  1. Thread finished.
  2. Thread finished.
  3. Thread finished.
  4. Thread finished.
  5. Thread finished.
  6. Thread finished.
  7. Thread finished.
  8. Thread finished.
  9.  
  10. sum = 0.7853981632, time = ms

● 用到的定义,pthread.h

  1. typedef struct pthread_mutex_t_ * pthread_mutex_t;
  2. typedef struct pthread_mutexattr_t_ * pthread_mutexattr_t;
  3.  
  4. PTW32_DLLPORT int PTW32_CDECL pthread_mutex_init(pthread_mutex_t * mutex, const pthread_mutexattr_t * attr);
  5. // 初始化互斥量,输入已经声明的一个 pthread_mutex_t 变量的指针及一个 pthread_mutexattr_t 属性指针,初始化完成后互斥量为解锁状态
  6.  
  7. PTW32_DLLPORT int PTW32_CDECL pthread_mutex_destroy(pthread_mutex_t * mutex); // 销毁用完的互斥量
  8.  
  9. PTW32_DLLPORT int PTW32_CDECL pthread_mutex_lock(pthread_mutex_t * mutex); // 锁定互斥量以访问临界区
  10.  
  11. 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. 安装 android x86 到 virtual box

    由于vmware无论怎么整,声音都出不了. 改用virtual box了. 很多注意点都参照了这篇文章 http://www.android-x86.org/documents/virtualboxh ...

  2. ContentNegotiatingViewResolver多种输出格式实例: json/jsp/xml/xls/pdf

    ContentNegotiatingViewResolver多种输出格式实例: json/jsp/xml/xls/pdf 本例用的是javaConfig配置 以pizza为例. json输出需要用到的 ...

  3. 无边框WPF窗体——允许拖动

    https://blog.csdn.net/zjcxhswill/article/details/38646525

  4. 《BAT前端进阶[师徒班]》学习总结

    这是一个培训课 是的,这是一个面向中级前端的培训班,但明显跟传统的填鸭式培训班不太一样.这边的老师都是大牛这是毫无疑问的,而且都是一线开发人员.而且课程一开始就说明了面向了是有1-3年有工作经验的前端 ...

  5. 编译安装zabbix3.2.5

    1. 配置lnmp环境 首先配置Nginx+mysql+php-fpm的系统环境,具体配置见另一篇文章 2. 编译安装zabbix 2.1 下载并解压zabbix 可以到zabbix官网下载zabbi ...

  6. Struts2基本使用(三)--数据交互

    Struts2中的数据交互 在Struts2中我们不必再使用request.getParameter()这种方式来获取前台发送到服务器的参数. 我们可以在服务器端的Java类中直接声明一个和前台发送数 ...

  7. 201621123006 《Java程序设计》第10周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结异常相关内容. 2. 书面作业 本次PTA作业题集异常 1. 常用异常 结合题集题目7-1回答 1.1 自己以前编写的代码中经常出现 ...

  8. java基础11天

    冒泡排序 相邻元素两两比较,大的往后放,第一次完毕,最大值出现在了最大索引处,第二次比较厚,最大值放在了倒数第二的位置,一直到第二个元素确定了,整个数组的顺序也就确定了 public class Ar ...

  9. New Concept English Two 10 25

    $课文23 新居 219. I had a letter from my sister yesterday. 昨天我收到了姐姐的一封信, 220. She lives in Nigeria. 她住在尼 ...

  10. Python 使用Microsoft SQL Server数据库

    软件环境: Windows 7 32bit Python 3.6  Download https://www.python.org/downloads/ 默认安装,并添加环境变量,一路Next ... ...