C - 并发问题

时间:2016-10-12 14:24:36

标签: c concurrency

我在Linux上使用C开发的代码存在问题。

我的结构如下:

typedef struct _my_sem {
    unsigned int valid;
    pthread_mutex_t m;
} my_sem;

以及以下函数(未报告错误管理):

void my_sem_init(my_sem *s);
void my_sem_destroy(my_sem *s);
void my_sem_lock(my_sem *s);
void my_sem_unlock(my_sem *s);


void my_sem_init(my_sem *s)
{
    pthread_mutex_create(&s->m);
    s->valid = 1;
}

void my_sem_destroy(my_sem *s)
{
    if (s->valid) {
        pthread_mutex_destroy(&s->m);
        s->valid = 0;
    }
}

void my_sem_lock(my_sem *s) {
    if (s->valid)
        pthread_mutex_lock(&s->m);
}

void my_sem_unlock(my_sem *s) {
    if (s->valid)
        pthread_mutex_unlock(&s->m);
}

此代码存在并发问题。如果有人试图锁定my_sem 并且,在有人摧毁对象的同时,呼叫将失败。

如何解决这个并发问题?

1 个答案:

答案 0 :(得分:1)

您提出的设计存在鸡与蛋的问题:成员my_sem.valid旨在向多个线程指示给定的互斥锁是否处于有效状态,但访问这些成员的多个线程会产生数据争用当其中一个访问是写入时,访问不是相互排序的(例如通过使用互斥锁保护访问)。

此外,您无法通过将valid的类型调整为可以原子更新的类型来解决此问题,因为互斥锁的初始化/完成以及valid的更新必须作为不可分割的单元执行使您的功能正常工作。此要求使用其他互斥锁,信号量或类似的同步辅助工具。

但是,您没有通过向结构添加其他同步对象来解决任何问题,因为如果您不能依赖现有互斥锁处于已知状态,那么您也不能依赖新对象的状态。因此,为了拯救这种设计,您需要一个全局互斥或信号量,四个函数中的每一个的主体都受其保护。

这是一个替代方案:不要发布未初始化的互斥锁,也不要销毁使用中(或可能仍在使用)的互斥锁。如果需要,您甚至可以使用互斥锁本身来保护测试是否仍在使用中,前提是您构造代码以避免在找到互斥锁后不再重新测试任何互斥锁的使用状态的可能性使用。这将需要更改您使用互斥锁,互斥锁管理功能以及struct的方式(如果您完全保留结构)。