我目前正在开发一个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更喜欢编写器,但仍然)
感谢您的任何见解
答案 0 :(得分:1)
到目前为止,没有人回答过,所以希望我能提供帮助。
要扩展死锁评论,请考虑经典示例......
T1: A -> B
T2: B -> A
只需将T1
的订单切换为...即可避免死锁(T2
和T2
可以取得进展)
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。但是,除非您完全理解各种内存排序排列,否则您几乎肯定会得到您不期望的行为。