mag*_*ras 5 c++ multithreading lifetime language-lawyer
我偶然发现了这个问题:线程访问另一个线程的堆栈。链接的问题是关于纯C的,但是我的主要语言是C ++,因此我尝试查找相同的规则是否适用于C ++。
我在C11草案中找到了本节N1570:
6.2.4.5其标识符声明为无链接且没有存储类说明符为static的对象与某些复合文字一样具有自动存储持续时间。尝试从与对象关联的线程之外的线程间接访问具有自动存储期限的对象的结果是 实现定义的。
我相信C ++ 20草案的相应部分N4810是[basic.stc.auto],并且没有提到这种情况。C ++ 11草案的这一部分与C ++ 20的文本完全相同。
在下面,[intro.multithread]我发现这句话带脚注:
程序中的每个线程都可以潜在地访问程序中的每个对象和函数。
具有自动或线程存储持续时间(6.6.5)的对象与一个特定线程相关联,并且只能由指针或引用(6.7.2)间接由另一个线程访问。
因此,我假设在C ++中从另一个线程访问具有自动存储持续时间的对象总是好的(直到对象生命周期的结束,并且当然也没有数据争用)。那是对的吗?
你是对的,你引用的 C++ 行有效地确定了 C++ 程序中的所有线程都看到相同的地址空间。C++ 对象模型的基石之一是每个活动对象都有一个唯一的地址[intro.object]/9。基于[intro.multithread]/1,您可以将对在一个线程的自动或线程本地存储中创建的对象的指针或引用传递给另一个线程,并从第二个线程访问该对象,只要该对象保证存在并且没有数据竞争......
有趣的是,C 标准似乎没有明确给出类似的保证。然而,不同的对象有不同的地址,而从程序中每个线程的角度来看,对象的地址是相同的,这一事实似乎仍然是语言规则的隐含的、必然的结果。C18 指定活动对象的地址不会改变 [6.2.4/2],任何对象指针都可以与指向void[6.5.9/2] 的指针进行比较,并且两个指针比较相等当且仅当它们指向到同一个对象[6.5.9/6]。存储类不是指针类型的一部分。因此,指向一个线程的自动存储中的对象的指针必须与指向另一线程的自动存储中的某个其他对象的指针以及指向具有不同存储持续时间的某个对象的指针进行比较。并且某个线程的自动存储中指向同一对象的任何两个指针必须比较相等,无论哪个线程从何处以何种方式获取这些指针。因此,指针的值在不同的线程中不可能有不同的含义。即使给定线程是否实际上可以通过指针访问另一个线程的自动存储中的对象可能是实现定义的,我也可以例如创建一个 global ,为其void*分配一个指向一个线程的自动存储对象的指针,并且,考虑到必要的同步,让另一个线程观察该指针并将其与其他指针进行比较。该标准向我保证,只有当我将它与指向同一对象的另一个指针(即另一个线程的自动存储中的同一对象)进行比较时,比较才能为真,并且在这种情况下它必须为真......
我无法告诉您决定让一个线程是否可以访问另一个线程的自动存储中的对象由实现定义的决定背后的确切理由。但人们可以想象一种假设的平台,其中,例如,仅分配堆栈的线程被授予对该堆栈的页面的访问权限,例如,出于安全原因。我不知道有任何实际的平台会出现这种情况。然而,即使在 x86 上,操作系统也可以轻松做到这一点。C 语言已经基于一些关于地址模型的、可以说是相当强的假设。我认为 C 标准委员会只是想避免在此基础上添加更多限制,这是一个很好的猜测……