有没有办法在C中使函数成为原子?

时间:2009-04-01 07:45:35

标签: c atomic operations

有没有办法在C中使函数成为原子。

我不是在寻找便携式解决方案。(平台寻找 - Win,Linux)

7 个答案:

答案 0 :(得分:14)

可能。

完全取决于你对“原子”的定义。

  • 在单核,深度嵌入式环境中,如果不涉及操作系统,通常可以禁用和启用中断。这可以用于允许函数对中断处理程序代码是原子的。但是如果你有一个多主总线,一个DMA引擎或一些可以独立写入内存的硬件设备,那么在某些情况下甚至屏蔽中断可能无法提供足够强大的保证。

  • 在RTOS(实时操作系统)环境中,OS内核通常提供低级同步原语,例如关键部分。关键部分是代码块,其“基本上”原子地行为,至少相对于所有其他关键部分。它通常是操作系统实现其他同步原语的基础。

  • 在多核环境中,通常可以使用称为自旋锁的低级原语。它用于防止进入相对于同一螺旋锁对象的其他用户必须是原子的代码块,并通过在紧密循环中阻塞等待CPU核心直到锁被释放(因此名称)来操作。

  • 在许多线程环境中,线程框架提供了更复杂的原语,如事件,信号量,互斥量和队列。它们与线程调度程序协作,以便等待发生某事的线程在满足条件之前根本不运行。这些可用于使函数的动作相对于共享同一同步对象的其他线程具有原子性。

一般规则是使用适合该任务的环境中可用的最高级别功能。在最好的情况下,可以使用现有的线程安全对象(如消息队列)来避免在代码中执行任何特殊操作。

答案 1 :(得分:3)

如果您想确保您的功能不会被信号中断,请使用sigprocmask()来屏蔽和取消屏蔽信号,尽管某些信号无法阻止(如SIGKILL)和阻止某些信号的行为信号(如SIGSEGV)未定义。

有关详细信息,请参阅man sigprocmask

答案 2 :(得分:1)

至少不便携。对于某些系统,您可以通过执行诸如转换机器中断之类的操作来处理它,以防止内核抢占您的功能。但这将非常困难,特别是对于非嵌入式系统。

答案 3 :(得分:1)

您需要特定于平台的支持 - 通过使用特殊的编译器内在函数来获取硬件指令,或者使用操作系统支持。 C和C ++都没有标准化的同步内容。

答案 4 :(得分:1)

用'原子'定义你的意思。你的意思是'原子',因为在你运行你的函数时没有选择其他进程或线程进行调度吗?或者,您的意思是在函数运行时,函数中引用的任何共享对象都不会被任何其他线程修改?

对于前者,您无法真正控制用户空间。如果您使用的是单CPU计算机,则可以可能通过将进程优先级提高到可能的最高优先级(来自用户空间)来保证原子性。但即便如此,也不能保证,因为您的调度算法可能仍然允许另一个进程运行。这样做的唯一可靠方法是从操作系统。对于单CPU机器,您将禁用中断。对于多核机器,您需要锁定总线并等待其他CPU上运行的所有进程被取消。

这里的问题是:为什么要保证原子性?通常,只有您的流程可能正在运行而不是其他流程的要求不应该存在于用户空间中。如果你想确保某些数据结构一次只能由一个线程访问,那么你应该使用一个可移植的线程库(例如pthread),并将你的函数作为一个关键部分。

答案 5 :(得分:1)

如果通过原子意味着“一次只有一个线程”,那么您可以使用“临界区块”(在Windows中)保护该功能。在Linux中,我使用互斥锁定/解锁来或多或少地模拟关键部分。

答案 6 :(得分:0)

您可能希望查看可能适用于Windows和Linux的POSIX信号量,互斥量等。

使用例如cygwin或minGW甚至可以在Linux和Windows之间编写可移植代码。

更好的是,您可以在Linux上创建Windows库:http://cdtdoug.blogspot.com/2009/05/mingw-cross-for-linux.html