Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在某个线程自身达到线程安全之前,您要降低多少?_C++_Multithreading_Thread Safety - Fatal编程技术网

C++ 在某个线程自身达到线程安全之前,您要降低多少?

C++ 在某个线程自身达到线程安全之前,您要降低多少?,c++,multithreading,thread-safety,C++,Multithreading,Thread Safety,我一直在想,在某些东西自动线程安全之前,你必须深入到每件事情的深度 快速示例: int dat = 0; void SetInt(int data) { dat = data; } 。。此方法是否被视为线程安全?我通常用互斥来包装我所有的set方法,只是为了确定,但每次我这样做时,我都忍不住认为这是一个无用的性能开销。我猜这一切都会分解为编译器生成的程序集?线程什么时候能够破译成代码?按照汇编指令还是按照代码行?线程能否在方法堆栈的设置或销毁过程中中断?像i++这样的指令会被认为是线程

我一直在想,在某些东西自动线程安全之前,你必须深入到每件事情的深度

快速示例:

int dat = 0;
void SetInt(int data)
{
    dat = data;
}
。。此方法是否被视为线程安全?我通常用互斥来包装我所有的set方法,只是为了确定,但每次我这样做时,我都忍不住认为这是一个无用的性能开销。我猜这一切都会分解为编译器生成的程序集?线程什么时候能够破译成代码?按照汇编指令还是按照代码行?线程能否在方法堆栈的设置或销毁过程中中断?像i++这样的指令会被认为是线程安全的吗?如果不是,那么++i呢

这里有很多问题——我不希望得到直接的回答,但是关于这个主题的一些信息会很好:)


[更新]因为我现在清楚了(thx to you guys一般来说,线程上下文切换可以在任何时候发生,在任意两个汇编语言指令之间。CPU完全不知道汇编语言如何映射到源代码。此外,对于多个处理器,其他指令可以同时在不同的CPU核上执行

话虽如此,在本例中,将CPU大小的字分配给内存位置通常是一个原子操作。这意味着从观察者(另一个线程)的角度来看,分配要么尚未开始,要么已经完成。没有中间状态


在多处理中有许多微妙之处,因此了解您工作的硬件和操作系统环境的可能性是很好的。

确保自动线程安全的唯一方法是确保不存在可变的共享状态。这就是为什么函数式编程正在获得这些吸引力天


因此,如果所有线程共享X,则必须确保X不会更改。任何更改的变量都必须是该线程的本地变量。

线程状态可以在任意两条机器指令之间更改。如果计算机能够在单个机器指令中执行赋值,则该赋值应在单个机器指令上是线程安全的处理器机器。一般来说,不能安全地假设赋值右侧的计算结果可以在单个指令中计算并存储在赋值左侧指定的位置。在某些处理器上,可能没有可用的内存到内存复制指令,并且数据可能不可用要先将eed加载到寄存器中。如果在加载指令和存储指令之间发生上下文切换,则赋值的结果是不确定的(不是线程安全的)。这是大多数指令集包含原子测试和设置操作的原因之一,该操作允许您将内存位置用作锁。这允许其他线程检查锁的可用性,并等待获得锁后再继续


在您的情况下,我不确定操作是否在硬件级别以线程安全的方式完成,因为多个相互竞争的线程执行分配的结果只是让其中一个线程最后完成存储并“获胜”如果你在右边执行任何类型的计算,但是,这涉及到使用多个变量的计算,那么我肯定会把它放在关键部分,因为你希望计算结果与计算开始时这些变量的状态一致。如果不是在关键部分n、 变量的值可能会在另一个线程的中途更改,您可能会得到任何一个线程都不可能得到的结果。

这是线程安全的,并且它不会在所有情况下都有效

假设dat变量保存数组中的元素计数。另一个线程开始使用dat变量扫描数组,并缓存其值。同时,更改dat变量的值。另一个线程再次扫描数组以执行其他操作。另一个线程是否执行以下操作d使用旧的dat值还是新的值?我们不知道,也不能确定。根据模块的编译情况,它可能使用旧的缓存值或新的值,这两种情况都有问题


您可以显式地将dat变量的值缓存在另一个线程上,以获得更可预测的结果。例如,如果此dat变量持有超时值,而您只写入此值,而另一个线程读取,那么我看不出这里有问题。即使是这种情况,您也不能说这是线程安全的!!!

以上代码是线程安全的

主要要注意的是静态(即共享)变量

除非通过某种锁机制(如互斥锁)管理更新,否则这些都不是线程安全的。这显然适用于任何操作系统提供的共享内存

因此,只要代码没有静态数据,它本身就是线程安全的


然后,您需要检查您使用的任何库或系统调用是否是线程安全的。这在大多数系统调用的文档中都有明确说明。

增量操作在x86处理器上是不安全的,因为它不是原子的。在windows上,您需要调用InterlockedIncrement函数。此函数生成完整内存barier。Also您可以使用“英特尔线程构建块”(tbb)库中的tbb::atomic。

在大多数平台(包括x86)上,“本机”数据类型(32位)的赋值是原子的。这意味着赋值将完全进行,并且您不会有“一半更新”dat变量的风险。但这是您得到的唯一保证

我不确定双数据类型的赋值。您可以在x86规范中查找,或者检查.NET是否允许