LFF*_*LFF 3 c performance gcc pthreads
我正在使用gcc(GCC)4.8.3 20140911在CentOS 7服务器上测试Linux上的pthread并行代码.
单线程版本很简单,它用于初始化10000*10000矩阵:
int main(int argc)
{
int size = 10000;
int * r = (int*)malloc(size * size * sizeof(int));
for (int i=0; i<size; i++) {
for (int j=0; j<size; j++) {
r[i * size + j] = rand();
}
}
free(r);
}
Run Code Online (Sandbox Code Playgroud)
然后我想看看并行代码是否可以提高性能:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
int size = 10000;
void *SetOdd(void *param)
{
printf("Enter odd\n");
int * r = (int*)param;
for (int i=0; i<size; i+=2) {
for (int j=0; j<size; j++) {
r[i * size + j] = rand();
}
}
printf("Exit Odd\n");
pthread_exit(NULL);
return 0;
}
void *SetEven(void *param)
{
printf("Enter Even\n");
int * r = (int*)param;
for (int i=1; i<size; i+=2) {
for (int j=0; j<size; j++) {
r[i * size + j] = rand();
}
}
printf("Exit Even\n");
pthread_exit(NULL);
return 0;
}
int main(int argc)
{
printf("running in thread\n");
pthread_t threads[2];
int * r = (int*)malloc(size * size * sizeof(int));
int rc0 = pthread_create(&threads[0], NULL, SetOdd, (void *)r);
int rc1 = pthread_create(&threads[1], NULL, SetEven, (void *)r);
for(int t=0; t<2; t++) {
void* status;
int rc = pthread_join(threads[t], &status);
if (rc) {
printf("ERROR; return code from pthread_join() is %d\n", rc);
exit(-1);
}
printf("Completed join with thread %d status= %ld\n",t, (long)status);
}
free(r);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
简单的代码运行大约0.8秒,而多线程版本运行大约10秒!!!!!!!
我在4核服务器上运行.但为什么多线程版本如此之慢?
rand()既不是线程安全也不是重入.所以你不能rand()在多线程应用程序中使用.
使用rand_r()替代这也是一个伪随机数发生器,是线程安全的.如果你在乎.使用rand_r()更短的执行时间结果我有2个内核(大约一半的时间作为单线程版本)系统上的代码.
在两个线程函数中,执行:
void *SetOdd(void *param)
{
printf("Enter odd\n");
unsigned int s = (unsigned int)time(0);
int * r = (int*)param;
for (int i=0; i<size; i+=2) {
for (int j=0; j<size; j++) {
r[i * size + j] = rand_r(&s);
}
}
printf("Exit Odd\n");
pthread_exit(NULL);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
更新:
虽然C和POSIX标准确实要求rand()是一个线程安全的函数,但glibc实现(在Linux上使用)实际上确实以线程安全的方式实现它.
291 __libc_lock_lock (lock);
292
293 (void) __random_r (&unsafe_state, &retval);
294
295 __libc_lock_unlock (lock);
296
Run Code Online (Sandbox Code Playgroud)
任何同步构造(互斥,条件变量等)都不利于性能,即代码中使用的此类构造的数量越少,性能就越好(当然,我们无法完全避免在多线程应用程序中确定它们).
因此,只有一个线程可以实际访问随机数生成器,因为两个线程一直在争夺锁定.这解释了为什么rand()导致多线程代码性能不佳.