8

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

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

4

7 回答 7

14

也许。

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

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

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

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

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

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

于 2009-04-01T08:09:35.087 回答
3

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

详情请参阅man sigprocmask

于 2009-04-01T07:49:40.640 回答
1

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

于 2009-04-01T07:47:24.967 回答
1

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

于 2009-04-01T07:49:44.963 回答
1

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

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

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

于 2009-04-01T13:58:26.667 回答
1

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

于 2009-04-01T15:48:55.140 回答
0

您可能想要研究 POSIX 信号量、互斥锁等,它们可能在 Windows 和 Linux 上都可以工作。

Using e.g. cygwin or minGW it's even possible to write portable code between Linux and Windows.

Even better you can create windows libs on Linux: http://cdtdoug.blogspot.com/2009/05/mingw-cross-for-linux.html

于 2009-05-18T17:11:52.817 回答