C交换指针竞争条件

时间:2015-08-05 20:29:17

标签: c multithreading pointers swap race-condition

我目前正在开发一个C程序,它或多或少是统一(de)多路复用器,用户在其中创建输入和输出之间的映射。虽然目的地只保留一次并且可用于所有来源,但是一个来源可以在不同的组中存在一次或多次(但不能在同一组中存在两次)

无论如何这是我的背景。因此,这些组很有用,我实现了一个在用户输入上切换组的功能。

当前活动组由指针" activeGroup"。

保持

每个输出目标都有一个线程等待输入并检查活动组的映射,因此使用" activeGroup"指针。

我今天的测试环境使用了ca. 2kHz输入,而最终用户输入可能更高(如1000kHz,考虑非活动源也可以发送数据)。没有明显的问题。

我现在的问题:

我应该为" activeGroup"使用RWLock吗?指针?原子指针的简单交换是一个问题吗?一般来说,我不介意一个或一百个输入包在短时间内到达错误的目的地,但是如果读取线程在绝对最糟糕的时刻读取,我可能会以某种方式出现分段错误吗?

写入指针的唯一函数:

bool activate_group(char *groupName){
    ... (get correct group to activate)
    if(newActive){
        if(activeGroup)
            activeGroup->isActive = false;
        // the only writing line to activegroup
        activeGroup = grp;
        grp->isActive = true;
        return true;
    }
    return false;
}

访问它的两个函数之一(非常相似)

void forward_sender(...){

    if(activeGroup && (input = FINDCORRECTINPUTSOUCEIN(activeGroup->mappingList)){

        snd_params par;
        par.sockfd = sockfd;
        par.msg = buffer;
        par.len = len;
        sendMultipleByInput(activeGroup->mappingList, sender, &par);
    }
}

另一个函数直接发送,这个可以发送多次。

如果activeGroup在其间切换,sendMultipleByInput将不会发送,因为它在现在新的活动映射列表中找不到设备之间的映射。

如果在当前实现中可能发生这种情况,我是否可以通过简单地访问activeGroup指针并将值复制到本地指针来避免它?

如果有的话,那会最小化,我猜?

由于性能是我的程序中的关键因素,Id喜欢尽可能多的同步方法,可能会减慢甚至导致死锁(不太可能在这里使用rwlock更喜欢编写器,但仍然)

感谢您的任何见解

1 个答案:

答案 0 :(得分:1)

到目前为止,没有人回答过,所以希望我能提供帮助。

要扩展死锁评论,请考虑经典示例......

T1: A -> B
T2: B -> A

只需将T1的订单切换为...即可避免死锁(T2T2可以取得进展)

T2: A -> B

绝对不应该为了避免死锁而避免锁定。你的直觉是关于使用rwlock的直觉,所以最好尽量减少关键部分的范围。

锁的性能不应该是一个问题。大多数锁实现都会避免进入内核。如果延迟确实是一个问题,那么有许多好的自旋锁实现。

不使用显式同步几乎当然会导致错误的行为。编写指向内存的指针通常是大多数体系结构上的原子操作(特别是x86),但是没有定义在核心/处理器之间进行读写的顺序。

例如,在您的代码中......

bool activate_group(char *groupName){
    ... (get correct group to activate)
    if(newActive){
        if(activeGroup)
            activeGroup->isActive = false;
        // the only writing line to activegroup
        activeGroup = grp;
        grp->isActive = true;
        return true;
    }
    return false;
}

和...

void forward_sender(...){

    if(activeGroup && (input = FINDCORRECTINPUTSOUCEIN(activeGroup->mappingList)){

        snd_params par;
        par.sockfd = sockfd;
        par.msg = buffer;
        par.len = len;
        sendMultipleByInput(activeGroup->mappingList, sender, &par);
    }
}

有许多不同的有效内存排序。特别是,在mappingList之前,没有任何内容可以保护activeGroup不被更新。实际订单几乎与程序订单无关。更重要的是,编译器将始终避免内存读写。因此,这些值很可能保留在寄存器中,甚至不会触及存储器。

!!! DANGER ZONE !!!

如果绝对需要无锁编程,C11增加了无锁atomics。但是,除非您完全理解各种内存排序排列,否则您几乎肯定会得到您不期望的行为。