我目前正在了解C中的pthreads
,并遇到了虚假分享的问题。我想我理解它的概念,并且我尝试过一些尝试。
以下是我一直在玩的简短程序。最后,我将把它改成一个程序来获取大量的int并且并行计算。
#include <stdio.h>
#include <pthread.h>
#define THREADS 4
#define NUMPAD 14
struct s
{
int total; // 4 bytes
int my_num; // 4 bytes
int pad[NUMPAD]; // 4 * NUMPAD bytes
} sum_array[4];
static void *worker(void * ind) {
const int curr_ind = *(int *) ind;
for (int i = 0; i < 10; ++i) {
sum_array[curr_ind].total += sum_array[curr_ind].my_num;
}
printf("%d\n", sum_array[curr_ind].total);
return NULL;
}
int main(void) {
int args[THREADS] = { 0, 1, 2, 3 };
pthread_t thread_ids[THREADS];
for (size_t i = 0; i < THREADS; ++i) {
sum_array[i].total = 0;
sum_array[i].my_num = i + 1;
pthread_create(&thread_ids[i], NULL, worker, &args[i]);
}
for (size_t i = 0; i < THREADS; ++i) {
pthread_join(thread_ids[i], NULL);
}
}
我的问题是,是否可以在不使用填充的情况下防止错误共享?这里struct s
的大小为64字节,因此每个结构都在它自己的缓存行上(假设缓存行是64字节)。我不确定如果没有填充,我怎么能实现并行性。
另外,如果我要在1000-50,000字节之间对不同大小的数组求和,我该如何防止错误共享?我可以使用类似的程序填写它吗?我目前的想法是将每个int从大数组中放入struct s
数组中,然后使用并行性来对它求和。但是,我不确定这是否是最佳解决方案。
答案 0 :(得分:1)
对问题进行分区:在worker()
中,求和一个局部变量,然后将局部变量添加到数组中:
static void *worker(void * ind) {
const int curr_ind = *(int *) ind;
int localsum = 0;
for (int i = 0; i < 10; ++i) {
localsum += sum_array[curr_ind].my_num;
}
sum_array[curr_ind].total += localsum;
printf("%d\n", sum_array[curr_ind].total);
return NULL;
}
循环后,这可能仍然存在错误共享,但每个线程一次。线程创建开销很多比单个缓存未命中更重要。当然,您可能希望有一个实际上耗费时间的循环,因为您当前的代码可以优化为:
static void *worker(void * ind) {
const int curr_ind = *(int *) ind;
int localsum = 10 * sum_array[curr_ind].my_num;
sum_array[curr_ind].total += localsum;
printf("%d\n", sum_array[curr_ind].total);
return NULL;
}
运行时肯定由printf()
中的线程创建和同步支配。