0

这是一个奇怪的问题,所以我会尝试提供很长的解释。
假设您在单核机器上运行。而且您有 2 个线程,可以说是互斥锁的经典生产者消费者问题。现在我想知道何时在单核机器上运行(所以 1 核没有 HT):
C++ 中有没有办法将这 2 个线程的执行融合为一个,以便互斥锁可以实现为简单的 int 存储/加载操作,而不是互斥。例如,这是否可行:统一线程中的生产者代码可以只是将内容放入循环缓冲区中,如果当前的 buffer_idx 高于 processes_idx,消费者代码将只从缓冲区中读取。

我知道这似乎是一个愚蠢的问题,但是很多嵌入式的东西仍然是 1 个核心。为简单起见,假设两个线程都是形式

while(! shutdown)
{
//...
}

只是把两个身体都放在一个大的时间里会按预期工作吗?

4

4 回答 4

1

您可以将生产者和消费者放在一个线程中。但是为了什么?它们的存储/加载操作将按顺序执行。他们之间总会有“和平”(不包括意外情况)。对于每个生产者存储操作,都会有消费者加载操作(如果没有条件语句,如果是,则生产者将停止并等待消费者代码加载所有内容,然后再次开始循环)。IMO,使用这种模型,您只能在代码中描述一小部分真实世界情况。

编辑:即使您在单核机器上,将您的逻辑拆分为多个线程也会使您获得比在一个线程中制作所有东西更好的性能。例如,虽然生产者会创建一些东西,但即使存储了一些东西,你的消费者也不会做任何事情,这样会浪费时间。想象一下,消费者加载完东西后,他必须把东西交给你逻辑的另一个元素,如果有很多其他元素,站在消费者之后,他们都在等待一个逻辑元素——生产者,然后等待消费者等。处理器在大多数情况下在线程之间切换所花费的时间少于生产或消费东西所需的时间。

于 2012-07-31T07:19:33.747 回答
0

这种“不受保护”的队列在嵌入的东西上很常见,例如。在线程和中断驱动程序之间进行通信。这样的驱动程序根本不能使用互斥体,(尽管它们通常可以发出信号量来使线程准备好,例如,当一个完整的协议包被推到这样一个不受保护的队列上时)。驱动程序通信的优点是一端绝对确定另一端不能中断它——驱动程序不能被线程中断。这使得确保索引/指针以“安全”顺序更新变得相当容易。

然而,在两个线程之间,事情变得更加困难。在操作索引/指针时,任一端都可以随时被另一端中断。我总是用互斥锁锁定这样的队列(我用于嵌入式通信的线程间队列无论如何都没有内部存储 - 消息本身具有内部转发链接,这使得无锁队列更加尴尬)。

于 2012-07-31T08:41:33.627 回答
0

由于一个接一个的无限循环意味着永远不会被执行,假设我们有“神奇的” GOTO 语句,它每次都会把我们跳到正确的地方。那么是的,将两个 while 循环放在一起可能会起作用,因为 GOTO 在这里本质上是一个监视器,尽管它可能不是您想要的。

另一方面,假设循环在正确的时间终止。将两个线程(不占用 CPU 时间)融合为一个,基本上可以消除您最初的问题。不需要互斥体,因为除了正在运行的进程本身之外,没有什么可以排除的。

另外要考虑的是单核系统也存在并发问题,它们在时间片中运行多个线程来模拟(在某种程度上)多核系统是如何工作的;相同的多路复用的东西应该可以直接转移。

于 2012-07-31T07:25:52.820 回答
0

你仍然必须同样小心。它不能同时运行两个线程,但是通过抢占式多任务处理,您的代码可能会被中断,而另一个线程可以随时运行,因此您仍然需要像一般情况下一样锁定事物。

一个常见的做法是在第一个线程上进行“存储在队列中”操作,而不是直接在另一个线程中调用“队列中的进程”函数(并且只有一个线程)。有可能通过正确的设计使代码在单个内核上运行单线程,如果您有多个内核,则运行多线程。这样可以避免在只有一个核心时必须锁定。

于 2012-07-31T07:26:00.277 回答