pthread 运行线程并发c
pthread running thread concurrently c
我需要在c中用pthread制作莱布尼茨算法,现在我有这段代码,但目前线程实现与顺序实现的时间相同,我认为不是运行并发.谁能看到错误。
谢谢!!
#include<stdio.h>
#include<math.h>
#include<pthread.h>
#include<stdlib.h>
#define NUM_THREADS 2
#define ITERATIONS 100000000
double result = 0.0;
void *leibniz(void *threadid){
int size = ITERATIONS/NUM_THREADS;
int start = (long)threadid * size;
int end = ((long)threadid+1) * size;
int i;
for(i = start; i<end; i++){
int denom = 2*i+1;
result += pow(-1.0, i) * (1.0/denom);
}
}
int main(){
pthread_t threads[NUM_THREADS];
long t;
int rc;
// CREATE
for(t=0;t<NUM_THREADS;t++){
rc = pthread_create(&threads[t], NULL, leibniz, (void *)t);
if(rc){
printf("ERROR: return code %d\n", rc);
}
}
// JOIN
for(t=0;t<NUM_THREADS;t++){
rc = pthread_join(threads[t], NULL);
if(rc){
printf("ERROR: return code %d\n", rc);
exit(-1);
}
}
printf("Pi %f\n", result*4);
exit(0);
}
多亏了 Jean-François Fabre,我做了这些更改,现在可以使用了!
double result=0.0;
void *leibniz(void *threadid){
double local = 0.0;
int size = ITERATIONS/NUM_THREADS;
int start = (long)threadid * size;
int end = ((long)threadid+1) * size;
int i;
for(i = start; i<end; i++){
local += (i%2==0 ? 1 : -1) * (1.0/(2*i+1));
}
result += local*4;
}
我会尝试回答。
即使您的应用程序是多线程的,也不能保证每个内核有 1 个 FPU。我对此知之甚少,但我认为某些 AMD 处理器实际上 共享 内核之间的 FPU。
因为你的循环基本上是加法和pow
,它是 99% 的 FPU 计算,所以如果 FPU 在你的计算机上共享,它解释了瓶颈。
您可以通过不调用 pow
来减少 FPU 的使用,而只是为了计算 -1
或 1
,这将是一个标量操作,并且可能会有所作为。如果 i
是奇数,只需使用 -1
,否则使用 1
,或者在每次迭代时取反外部 1/-1 变量。
另外为了避免race conditions,将结果累加到一个local result中,最后再相加(最后用mutex保护相加会更好)
double result = 0.0;
void *leibniz(void *threadid){
double local = 0.0;
int size = ITERATIONS/NUM_THREADS;
int start = (long)threadid * size;
int end = ((long)threadid+1) * size;
int i;
for(i = start; i<end; i++){
int denom = 2*i+1;
// using a ternary/scalar speeds up the "pow" computation, multithread or not
local += (i%2 ? -1 : 1) * (1.0/denom);
}
// you may want to protect that addition with a pthread_mutex
// start of critical section
result += local;
// end of critical section
}
http://wccftech.com/amd-one-fpu-per-core-design-zen-processors/
我在 Windows 运行 Visual Studio,我还没有安装 pthreads,所以我创建了一个使用 Windows 线程的测试程序。我将计算拆分为一个计算所有正项的函数和一个计算所有负项的函数。双精度不是问题,因为正和 < 22,负和 > -19。
处理器是 Intel 3770K 3.5ghz(每个内核都有自己的 FPU)。我测试了连续调用这两个函数与对第二个函数使用单独的线程相比,双线程情况比单线程情况快两倍,单线程 ~ 0.360 秒,双线程 ~= 0.180 秒。
#include <stdio.h>
#include <time.h>
#include <windows.h>
static HANDLE ht1; /* thread handle */
static DWORD WINAPI Thread0(LPVOID); /* thread functions */
static DWORD WINAPI Thread1(LPVOID);
static clock_t ctTimeStart; /* clock values */
static clock_t ctTimeStop;
static double dTime;
static double pip; /* sum of positive terms */
static double pim; /* sum of negative terms */
static double pi; /* pi */
int main()
{
ctTimeStart = clock();
Thread0(NULL);
Thread1(NULL);
ctTimeStop = clock();
dTime = (double)(ctTimeStop - ctTimeStart) / (double)(CLOCKS_PER_SEC);
pip *= 4.; /* pip < 22 after *= 4. */
pim *= 4.; /* pim > -19 after *= 4. */
pi = pip + pim;
printf("%.16lf %.16lf %.16lf %2.5lf secs\n", pi, pip, pim, dTime);
ctTimeStart = clock();
ht1 = CreateThread(NULL, 0, Thread1, 0, 0, 0);
Thread0(NULL);
WaitForSingleObject(ht1, INFINITE); // wait for thead 1
ctTimeStop = clock();
dTime = (double)(ctTimeStop - ctTimeStart) / (double)(CLOCKS_PER_SEC);
pip *= 4.; /* pip < 22 after *= 4. */
pim *= 4.; /* pim > -19 after *= 4. */
pi = pip + pim;
printf("%.16lf %.16lf %.16lf %2.5lf secs\n", pi, pip, pim, dTime);
CloseHandle(ht1);
return 0;
}
DWORD WINAPI Thread0(LPVOID lpVoid)
{
double pp = 0.; /* local sum */
int j;
for(j = 200000001; j >= 0; j -= 4)
pp += 1. / (double)(j);
pip = pp; /* store sum */
return 0;
}
DWORD WINAPI Thread1(LPVOID lpVoid)
{
double pm = 0.; /* local sum */
int j;
for(j = 200000003; j >= 0; j -= 4)
pm -= 1. / (double)(j);
pim = pm; /* store sum */
return 0;
}
我需要在c中用pthread制作莱布尼茨算法,现在我有这段代码,但目前线程实现与顺序实现的时间相同,我认为不是运行并发.谁能看到错误。
谢谢!!
#include<stdio.h>
#include<math.h>
#include<pthread.h>
#include<stdlib.h>
#define NUM_THREADS 2
#define ITERATIONS 100000000
double result = 0.0;
void *leibniz(void *threadid){
int size = ITERATIONS/NUM_THREADS;
int start = (long)threadid * size;
int end = ((long)threadid+1) * size;
int i;
for(i = start; i<end; i++){
int denom = 2*i+1;
result += pow(-1.0, i) * (1.0/denom);
}
}
int main(){
pthread_t threads[NUM_THREADS];
long t;
int rc;
// CREATE
for(t=0;t<NUM_THREADS;t++){
rc = pthread_create(&threads[t], NULL, leibniz, (void *)t);
if(rc){
printf("ERROR: return code %d\n", rc);
}
}
// JOIN
for(t=0;t<NUM_THREADS;t++){
rc = pthread_join(threads[t], NULL);
if(rc){
printf("ERROR: return code %d\n", rc);
exit(-1);
}
}
printf("Pi %f\n", result*4);
exit(0);
}
多亏了 Jean-François Fabre,我做了这些更改,现在可以使用了!
double result=0.0;
void *leibniz(void *threadid){
double local = 0.0;
int size = ITERATIONS/NUM_THREADS;
int start = (long)threadid * size;
int end = ((long)threadid+1) * size;
int i;
for(i = start; i<end; i++){
local += (i%2==0 ? 1 : -1) * (1.0/(2*i+1));
}
result += local*4;
}
我会尝试回答。
即使您的应用程序是多线程的,也不能保证每个内核有 1 个 FPU。我对此知之甚少,但我认为某些 AMD 处理器实际上 共享 内核之间的 FPU。
因为你的循环基本上是加法和pow
,它是 99% 的 FPU 计算,所以如果 FPU 在你的计算机上共享,它解释了瓶颈。
您可以通过不调用 pow
来减少 FPU 的使用,而只是为了计算 -1
或 1
,这将是一个标量操作,并且可能会有所作为。如果 i
是奇数,只需使用 -1
,否则使用 1
,或者在每次迭代时取反外部 1/-1 变量。
另外为了避免race conditions,将结果累加到一个local result中,最后再相加(最后用mutex保护相加会更好)
double result = 0.0;
void *leibniz(void *threadid){
double local = 0.0;
int size = ITERATIONS/NUM_THREADS;
int start = (long)threadid * size;
int end = ((long)threadid+1) * size;
int i;
for(i = start; i<end; i++){
int denom = 2*i+1;
// using a ternary/scalar speeds up the "pow" computation, multithread or not
local += (i%2 ? -1 : 1) * (1.0/denom);
}
// you may want to protect that addition with a pthread_mutex
// start of critical section
result += local;
// end of critical section
}
http://wccftech.com/amd-one-fpu-per-core-design-zen-processors/
我在 Windows 运行 Visual Studio,我还没有安装 pthreads,所以我创建了一个使用 Windows 线程的测试程序。我将计算拆分为一个计算所有正项的函数和一个计算所有负项的函数。双精度不是问题,因为正和 < 22,负和 > -19。
处理器是 Intel 3770K 3.5ghz(每个内核都有自己的 FPU)。我测试了连续调用这两个函数与对第二个函数使用单独的线程相比,双线程情况比单线程情况快两倍,单线程 ~ 0.360 秒,双线程 ~= 0.180 秒。
#include <stdio.h>
#include <time.h>
#include <windows.h>
static HANDLE ht1; /* thread handle */
static DWORD WINAPI Thread0(LPVOID); /* thread functions */
static DWORD WINAPI Thread1(LPVOID);
static clock_t ctTimeStart; /* clock values */
static clock_t ctTimeStop;
static double dTime;
static double pip; /* sum of positive terms */
static double pim; /* sum of negative terms */
static double pi; /* pi */
int main()
{
ctTimeStart = clock();
Thread0(NULL);
Thread1(NULL);
ctTimeStop = clock();
dTime = (double)(ctTimeStop - ctTimeStart) / (double)(CLOCKS_PER_SEC);
pip *= 4.; /* pip < 22 after *= 4. */
pim *= 4.; /* pim > -19 after *= 4. */
pi = pip + pim;
printf("%.16lf %.16lf %.16lf %2.5lf secs\n", pi, pip, pim, dTime);
ctTimeStart = clock();
ht1 = CreateThread(NULL, 0, Thread1, 0, 0, 0);
Thread0(NULL);
WaitForSingleObject(ht1, INFINITE); // wait for thead 1
ctTimeStop = clock();
dTime = (double)(ctTimeStop - ctTimeStart) / (double)(CLOCKS_PER_SEC);
pip *= 4.; /* pip < 22 after *= 4. */
pim *= 4.; /* pim > -19 after *= 4. */
pi = pip + pim;
printf("%.16lf %.16lf %.16lf %2.5lf secs\n", pi, pip, pim, dTime);
CloseHandle(ht1);
return 0;
}
DWORD WINAPI Thread0(LPVOID lpVoid)
{
double pp = 0.; /* local sum */
int j;
for(j = 200000001; j >= 0; j -= 4)
pp += 1. / (double)(j);
pip = pp; /* store sum */
return 0;
}
DWORD WINAPI Thread1(LPVOID lpVoid)
{
double pm = 0.; /* local sum */
int j;
for(j = 200000003; j >= 0; j -= 4)
pm -= 1. / (double)(j);
pim = pm; /* store sum */
return 0;
}