这是我之前的问题的扩展
How does blocking mode in unix/linux sockets works?
我现在从Internet收集的内容,调用阻塞调用的所有进程都会进入休眠状态,直到调度程序找到解除阻塞的原因。原因可以从缓冲区空白到缓冲区满,也可以是任何其他条件。
但是,这可以成为实时的有效方式,让我们说硬/实时应用程序?由于当解除阻塞条件成立时,进程未被解除阻塞,而是当调度程序给出他的CPU切片时,并且解除阻塞条件都为真。
好像你想要一个响应式解决方案,我不这个“旋转锁”或“忙等待”是正确的方法,CPU切片被浪费,整个系统将无法响应或可能很差响应性。
有人可以清除这些相互矛盾的想法。
答案 0 :(得分:39)
在调度程序唤醒你之前进入睡眠是正常/首选的事情。
旋转(等待的替代方式,不睡觉)不太常见,并具有以下效果:
保持CPU忙碌,并阻止其他线程使用CPU(除非旋转线程完成其时间片并被禁止使用)
当你正在等待的事情发生时,可以停止旋转(因为你不断检查那个事件,而你不需要花时间来唤醒它,因为你已经醒了)
不调用进入睡眠状态并再次唤醒所需的CPU结构
如果延迟的长度非常短,则旋转可以比进入睡眠更有效(更少的总CPU)(例如,如果延迟仅在执行100时延迟) CPU指令)。
答案 1 :(得分:4)
旋转锁定会烧毁CPU和轮询的资源路径,以便在未发生所需事件时继续浪费资源。
阻止操作最重要的不同之处在于保留CPU和相关资源路径,并在预期所需事件的资源上安装某种形式的wait
。
在多任务处理或多线程/处理器环境中(通常情况下很长一段时间),在没有到达所需事件的情况下可能进行其他操作时,烧毁CPU和资源访问路径会导致处理能力的极大浪费和时间。
当我们有一个超线程系统(就像我认为你在你的问题中指的那样)时,重要的是要注意切片CPU线程的粒度非常高。我会伸出脖子观察所有事件 - 你会倾向于阻止它 - 会花费足够的时间来产生,补偿他们在解锁之前必须等待的小时间片。
我认为J-16
的观点是睡眠(阻塞)线程在阻塞状态下未使用其代码和数据空间的情况。这可能会使系统放弃资源(如数据/代码缓存),然后在释放块时需要重新填充资源。因此,在条件允许的情况下,区块可能会造成更多的资源浪费
这也是一个有效的说明,应在设计和实施中进行检查
但是,在大多数情况下,阻塞通常比自旋锁更好。
答案 2 :(得分:1)
如果在您的应用程序的用例中,上下文切换比吃几个CPU周期更昂贵,因为您的条件将保证在短时间内得到满足 时间,然后忙着等待可能对你有好处。
否则,您可以通过休眠或cond_wait()
强行放弃CPU。
我可以想到强制上下文切换的另一个场景如下:
while(condition)
sleep(0);
答案 3 :(得分:0)
首先,您有一种误解:
阻止呼叫不是“忙等待”或“旋转锁定”。阻塞调用是可以访问的 - 这意味着CPU可以处理其他任务,不会浪费cpu。
关于阻止来电的问题
阻止调用更容易 - 它们易于理解,更易于开发,更易于调试。
但他们是资源匮乏。如果你不使用线程,它会阻止其他客户端;如果使用线程,每个线程将占用内存和其他系统资源。即使你有足够的内存,切换线程也会使缓存变冷并降低性能。
这是一种权衡 - 更快的开发和可维护性?或可扩展性。
答案 4 :(得分:0)
我将努力做到这一点,因为这里通过其他答案提供了足够的解释,是的,从所有这些答案中学习,我认为应该是完整的图片。 ---
根据我的权衡,应该在系统的响应性和吞吐量之间进行权衡。
响应能力 - 可以从两个角度考虑
我认为对于系统的响应性,阻止呼叫是最好的方法。因为它给处于就绪队列中的其他进程的CPU,当阻塞调用处于阻塞状态时。
当然,对于特定进程或每进程响应,我们将考虑忙等待/自旋锁模型。
现在,再次提高整体系统响应能力我们无法减少调度程序的时间片(细粒度),因为这会在上下文切换中浪费太多的CPU资源。因此系统的吞吐量将大幅减少。当然,很明显阻塞模型会增加系统的吞吐量,因为被阻塞的调用不会消耗CPU切片并将其提供给就绪队列中的另一个/下一个进程。
我认为最好的办法是 - 设计一个系统,每个流程的响应能力都在考虑,而不会影响整体响应能力和吞吐量 - 通过实施基于优先级的调度程序,考虑优先级倒置问题,如果增加复杂性不会打扰你:)。
答案 5 :(得分:-2)
//改编的ASPI原始源代码......
DWORD startStopUnit (HANDLE handle, BOOL bLoEj, BOOL bStart)
{
DWORD dwStatus;
HANDLE heventSRB;
SRB_ExecSCSICmd s;
//here
heventSRB = CreateEvent (NULL, TRUE, FALSE, NULL);
memset (&s, 0, sizeof (s));
s.SRB_Cmd = SC_EXEC_SCSI_CMD;
s.SRB_HaID = 0;
s.SRB_Target = 0;
s.SRB_Lun = 0;
s.SRB_Flags = SRB_EVENT_NOTIFY;
s.SRB_SenseLen = SENSE_LEN;
s.SRB_CDBLen = 6;
s.SRB_PostProc = (LPVOID) heventSRB;
s.CDBByte[0] = 0x1B;
s.CDBByte[4] |= bLoEj ? 0x02 : 0x00;
s.CDBByte[4] |= bStart ? 0x01 : 0x00;
ResetEvent (heventSRB);
dwStatus = SPTISendASPI32Command (handle,(LPSRB) & s);
if (dwStatus == SS_PENDING)
{
//and here, don´t know a better way to wait for something to finish without processor cicles
WaitForSingleObject (heventSRB, DEFWAITLEN);
}
CloseHandle (heventSRB);
if (s.SRB_Status != SS_COMP)
{
printf("Erro\n");
return SS_ERR;
}
printf("nao Erro\n");
return s.SRB_Status;
}