【发布时间】:2019-04-10 17:57:12
【问题描述】:
我尝试实现计算某种积分的程序。为了加快计算速度,一个创建多个进程,另一个使用多个线程。在我的程序中,每个进程将一个双精度值添加到共享内存中,每个线程通过指针添加一个双精度值。
这是我的问题。加法操作显然从内存中加载值,向其中添加一个值,然后将结果存储到内存中。所以看起来我的代码很容易出现生产者-消费者问题,因为许多进程/线程访问相同的内存区域。但是,我找不到有人使用信号量或互斥锁来实现简单累加器的情况。
// creating processes
while (whatever)
{
pid = fork();
if (pid == 0)
{
res = integralproc(clist, m, tmpcnt, tmpleft, tmpright);
*(createshm(shm_key)) += res;
exit(1);
}
}
// creating or retrieving shared memory
long double* createshm(int key)
{
int shm_id = -1;
void* shm_ptr = (void*)-1;
while (shm_id == -1)
{
shm_id = shmget((key_t)key, sizeof(long double), IPC_CREAT | 0777);
}
while (shm_ptr == (void*)-1)
{
shm_ptr = shmat(shm_id, (void*)0, 0);
}
return (long double*)shm_ptr;
}
// creating threads
while (whatever)
{
threadres = pthread_create(&(targs[i]->thread_handle), NULL, integral_thread, (void*)targs[i]);
}
// thread function. targ->resptr is pointer that we add the result to.
void *integral_thread(void *arg)
{
threadarg *targ = (threadarg*)arg;
long double res = integralproc(targ->clist, targ->m, targ->n, targ->left, targ->right);
*(targ->resptr) += res;
//printf("thread %ld calculated %Lf\n", targ->i, res);
pthread_exit(NULL);
}
所以我以这种方式实现它,到目前为止,无论我创建多少进程/线程,结果都好像从未发生过一样。 我担心我的代码可能仍然存在潜在危险,只是几乎不在我的视线范围内。 这段代码真的不受这些问题的影响吗?还是我忽略了什么,应该修改代码?
【问题讨论】:
-
除非您使用某种锁,否则从技术上讲它是未定义的,或者最好使计数器成为原子并对其使用原子操作。
-
我建议为整数编写一个简单的程序。让多个线程在不同步的情况下并行递增 (
volatile) 整数固定次数。将结果与固定的增量数乘以线程数进行比较。阅读有关原子性和未定义行为的信息。 -
为什么不为每个线程设置一个单独的计数器并在最后合并它们?
-
另外,要非常小心,不要将 volatile 用作穷人的原子,这只是对 volatile 的错误使用。 C 有一个定义明确的线程内存模型标准化,基本上它采用了标准 C++ 并发/原子性模型。
标签: c pthreads fork shared-memory