▶ 一个简单的 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. <<网络是怎样连接的>>笔记第5章 防火墙,缓存服务器

    第5章 服务器防火墙,缓存服务器 部署地点 防火墙结构和原理 通过将请求平均分配给多台服务器来平衡负载 利用缓存服务器分担负载(客户端也可以部署缓存服务器, 缓存服务器用法很多) 内容分发服务(从缓存 ...

  2. 各种排序算法思想复杂度及其java程序实现

    一.冒泡排序(BubbleSort)1. 基本思想: 设排序表长为n,从后向前或者从前向后两两比较相邻元素的值,如果两者的相对次序不对(A[i-1] > A[i]),则交换它们, 其结果是将最小 ...

  3. Integer与int的种种比较你知道多少

    如果面试官问Integer与int的区别:估计大多数人只会说道两点,Ingeter是int的包装类,int的初值为0,Ingeter的初值为null. 但是如果面试官再问一下Integer i = 1 ...

  4. 从0开始springboot

    http://412887952-qq-com.iteye.com/blog/2291500

  5. python自动化运维之路2

    list列表 列表是我们最以后最常用的数据类型之一,通过列表可以对数据实现最方便的存储.修改等操作 #!/usr/bin/env python # _*_ encoding:utf-8 _*_ # a ...

  6. Android 遍历全国地区位置(一)

    1.布局 choose_area.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayo ...

  7. Tomcat : Invalid character found in the request target

    Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC ...

  8. 【LeetCode 36_哈希表】Valid Sudoku

    //occupyed_1检查行是否占用 //occupyed_2检查列是否占用 //occupyed_3检查块是否占用 bool isValidSudoku(vector<vector<c ...

  9. pandas 之 concat

    本文摘自:http://pandas.pydata.org/pandas-docs/stable/merging.html 前提: ide: liuqian@ubuntu:~$ ipython 准备: ...

  10. 使用C++实现二叉搜索树的数据结构

    需要注意的地方: ①二叉搜索树删除一个指定结点R,若R为叶子结点,则将R的父结点中指向R的指针改为指向nullptr:若R的左右子结点一个为空,一个非空,则将R的父结点中指向R的指针改为指向R的非空子 ...