[英]Is implementing semaphore or mutex necessary for simple counter?
我试着实施一些计算积分的程序。 为了加快计算速度,一个创建多个进程,另一个使用多个线程。 在我的程序中,每个进程将一个双精度值添加到共享内存中,每个线程通过指针添加一个双精度值。
这是我的问题。 很明显,添加操作会从内存中加载值,然后向其中添加一个值,然后将结果存储到内存中。 因此,由于许多进程/线程访问同一内存区域,因此我的代码似乎很容易出现生产者-消费者问题。 但是,我找不到有人使用信号量或互斥量来实现简单的累加器的情况。
// 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);
}
所以我以这种方式实现了它,到目前为止,无论我创建了多少个进程/线程,结果都好像从未发生过。 我担心我的代码可能仍然很危险,只是几乎看不见。 这段代码对这些问题真的安全吗? 还是我忽略了某些内容,应该修改代码?
如果您的线程都在targ->resptr
更新同一对象(即,每个线程的targ->resptr
指向同一件事),那么可以-您确实有数据争用,并且您会看到不正确的结果(可能是“丢失更新” ”中恰好同时完成的两个线程尝试更新总和,而其中只有一个有效)。
您可能还没有看到它,因为您的*targ->resptr
integralproc()
函数的执行时间很长,因此多个线程同时到达更新*targ->resptr
的机会很低。
尽管如此,您仍然应该解决该问题。 您可以在总和更新周围添加互斥锁/解锁:
pthread_mutex_lock(&result_lock);
*(targ->resptr) += res;
pthread_mutex_unlock(&result_lock);
(这不会影响解决方案的效率,因为您在每个线程的生命周期中仅锁定和解锁一次)。
或者,您可以让每个线程在其自己的线程参数结构中记录其自己的部分结果:
targ->result = res;
然后,一旦工作线程全部被pthread_join()
编辑,创建它们的父线程就可以遍历所有线程参数结构并累加部分结果。
这里不需要额外的锁定,因为工作线程不会互相访问其他结果变量,并且pthread_join()
提供了设置结果的工作线程与读取结果的父线程之间的必要同步。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.