假设我有多个线程,并且所有线程几乎同时调用相同的函数。
是否存在一个只允许一个函数实例的调用约定?我的意思是第二个线程调用的函数只有在第一个线程调用的函数返回后才会启动。
或者这些调用约定编译器是否具体?我没有很多使用它们的经验。
答案 0 :(得分:4)
Calling convention定义了堆栈和&寄存器用于实现函数调用。因为每个线程都有自己的堆栈和寄存器,同步线程和调用约定是分开的事情。
要防止多个线程同时执行相同的代码,您需要mutex。在你的函数示例中,你通常会在函数代码中放置互斥锁并解锁,围绕你不希望线程同时执行的语句。
一般而言:普通代码(包括函数调用)不了解操作系统的线程。通过使用互斥锁,您可以使用管理线程运行的系统。更多细节只是谷歌搜索。
请注意,C11, the new C standard revision确实包含多线程支持。但这并没有改变一般概念;它只是意味着您可以使用C库函数而不是特定于操作系统的函数。
答案 1 :(得分:4)
(如果你不关心穿线的话,请跳到最底层)
如前所述,这不是“调用约定”,而是计算的一般问题:concurrency。并且两个或多个线程一次可以进入共享区域并具有不同结果的特定情况称为race condition(并且还扩展到电子设备和其他区域)。
线程化的难点在于计算是一种确定性事件,但是当涉及线程时,它会增加一定程度的不确定性,这些不确定性因平台/操作系统而异。
单线程事件将保证它可以始终以相同的顺序执行所有任务,但是当您有多个线程,并且顺序取决于它们完成任务的速度,共享其他想要使用该任务的应用程序CPU,然后底层硬件会影响结果。
没有太多“确定的线程化方法”,因为有处理个别案例的技术,工具和库。
最着名的技术是使用信号量(或锁),最着名的信号量是互斥量,它只允许一个线程一次访问共享空间,具有一种“标志”一旦线程进入就会引发。
if (locked == NO)
{
locked = YES;
// Do ya' thing
locked = NO;
}
上面的代码,虽然看起来它可以工作,但它不能保证两个线程都通过if ()
然后设置变量(哪些线程可以轻松完成)的情况。因此,这种操作有硬件支持,可以保证只有一个线程可以执行它:testAndSet
操作,检查然后,如果可用,设置变量。 (来自Here's the x86 instruction)
在锁和信号量的同一个静脉上,还有读写锁,它允许多个读者和一个作者,特别适用于低波动性的东西。并且还有许多其他变体,一些限制了X线程数量等等。
但总的来说,锁是蹩脚的,因为它们基本上强制多线程的序列化,其中线程实际上需要卡住试图获得锁定(或只是测试并离开)。有点打败多线程的目的,不是吗?
线程方面的最佳解决方案是最小化线程需要使用的共享空间量,可能完全消除它。当波动率较低时,可以使用rwlocks
,尝试“尝试并离开”某种线程,检查锁定是否已启动,然后如果不是等则消失,等等。
正如我的操作系统老师曾经说过的那样(以禅宗的方式):“最好的锁定是你可以避免的那种”。
现在,线程很难,没有解决方法,这就是为什么有这样的问题处理模式的原因,Thread Pool Pattern是一个很受欢迎的模式,至少在iOS中引入Grand Central Dispatch (GCD)。
不是让一堆线程无法运行并在整个地方排队,而是让我们拥有一组线程,等待“池”中的任务,以及有事情要做的队列,理想情况下,任务应该是'彼此重叠。
现在,线程模式并没有解决之前讨论过的问题,但它改变了范例,使其更容易处理,从精神上来说。您只需将焦点切换到“需要执行的任务”以及哪个线程正在执行的操作变得无关紧要,而不必考虑“需要执行此类等的线程”。
同样,游泳池不会解决您的所有问题,但它会让他们更容易理解。更容易理解可能会带来更好的解决方案。
上面提到的所有理论事项都已经实现,在POSIX级别(semaphore.h,pthreads.h等,pthreads有一个非常好的r / w锁定函数),尝试阅读它们。
(编辑:我认为这个帖子是关于Obj-C,而不是普通的C,编辑了所有的Foundation和GCD的东西)