简体   繁体   English

是否需要为简单计数器实现信号量或互斥量?

[英]Is implementing semaphore or mutex necessary for simple counter?

I tried implementing programs that calculates sort of integral. 我试着实施一些计算积分的程序。 And in order to speed up the computation, one creates multiple processes and other uses multiple threads. 为了加快计算速度,一个创建多个进程,另一个使用多个线程。 In my program, each process adds a double value into shared memory and each thread adds a double value through the pointer. 在我的程序中,每个进程将一个双精度值添加到共享内存中,每个线程通过指针添加一个双精度值。

Here's my question. 这是我的问题。 The add operation obviously loads the value from memory, add a value to that, and stores the result to the memory. 很明显,添加操作会从内存中加载值,然后向其中添加一个值,然后将结果存储到内存中。 So it seems my code is quite prone to producer-consumer problem as many processes/threads access the same memory area. 因此,由于许多进程/线程访问同一内存区域,因此我的代码似乎很容易出现生产者-消费者问题。 However, I couldn't find the case where somebody used semaphores or mutexes to implement a simple accumulator neither. 但是,我找不到有人使用信号量或互斥量来实现简单的累加器的情况。

// 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);
}

So I implemented it this way, and so far no matter how many processes/threads I make, the result was as if it never happened. 所以我以这种方式实现了它,到目前为止,无论我创建了多少个进程/线程,结果都好像从未发生过。 I'm concerned that my codes may still be potentially dangerous, just barely out of my sight. 我担心我的代码可能仍然很危险,只是几乎看不见。 Is this code truly safe from any of these problems? 这段代码对这些问题真的安全吗? Or am I overlooking at something and should the code be revised? 还是我忽略了某些内容,应该修改代码?

If your threads are all racing to update the same object (ie, the targ->resptr for each thread points at the same thing), then yes - you do have a data race and you can see incorrect results (likely, "lost updates" where two threads that happen to finish at the same time try to update the sum, and only one of them is effective). 如果您的线程都在targ->resptr更新同一对象(即,每个线程的targ->resptr指向同一件事),那么可以-您确实有数据争用,并且您会看到不正确的结果(可能是“丢失更新” ”中恰好同时完成的两个线程尝试更新总和,而其中只有一个有效)。

You probably haven't seen this because the execution time of your integralproc() function is long, so the chances of multiple threads simultaneously getting to the point of updating *targ->resptr is low. 您可能还没有看到它,因为您的*targ->resptr integralproc()函数的执行时间很长,因此多个线程同时到达更新*targ->resptr的机会很低。

Nonetheless, you should still fix the problem. 尽管如此,您仍然应该解决该问题。 You can either add a mutex lock/unlock around the sum update: 您可以在总和更新周围添加互斥锁/解锁:

pthread_mutex_lock(&result_lock);
*(targ->resptr) += res;
pthread_mutex_unlock(&result_lock);

(This shouldn't affect the efficiency of the solution, since you are only locking and unlocking once in the lifetime of each thread). (这不会影响解决方案的效率,因为您在每个线程的生命周期中仅锁定和解锁一次)。

Alternatively, you can have each thread record its own partial result in its own thread argument structure: 或者,您可以让每个线程在其自己的线程参数结构中记录其自己的部分结果:

targ->result = res;

Then, once the worker threads have all been pthread_join() ed the parent thread that created them can just go through all the thread argument structures and add up the partial results. 然后,一旦工作线程全部被pthread_join()编辑,创建它们的父线程就可以遍历所有线程参数结构并累加部分结果。

No extra locking is needed here because the worker threads don't access each others result variable, and the pthread_join() provides the necessary synchronisation between the worker setting the result and the parent thread reading it. 这里不需要额外的锁定,因为工作线程不会互相访问其他结果变量,并且pthread_join()提供了设置结果的工作线程与读取结果的父线程之间的必要同步。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM