TL;DR:当数据竞赛同时调用两个可能不同的函数时,说一个特定的函数是‘线程安全’是什么意思?这个问题在人们告诉"const意思/暗示C++11中的线程安全“[1][2]的上下文中特别重要。
请考虑以下示例:
class X {
int x, y; // are some more complex type (not supported by `std::atomic`)
std::mutex m;
public:
void set_x (int new_x) {x = new_x;} // no mutex
void get_x () const {return x;}
void set_y (int new_y) {
std::lock_guard<std::mutex> guard(m); // guard setter with mutex
y = new_y;
}
void get_y () const {return y;}
}set_x 线程安全吗?
当然,set_x不是线程安全的,因为从两个线程同时调用它会导致数据竞争。
是 ** get_y 和 set_y 线程安全?
有两个可能的理由:
get_x/get_y/set_y不会导致数据竞争。get_x (或get_y)和set_x (或set_y)会同时导致数据竞争。这三种功能中哪一种是正确的?
问题摘要
哪种推理是正确的?
set_x/get_x上工作,但是对于set_y/get_y失败,因为这将得出结论:set_y和get_y是线程安全的,但是类Y并不是因为从两个线程同时调用set_y和get_y而导致数据竞争。相关螺纹
请注意,我阅读了以下相关的线程:
发布于 2021-05-01 14:06:27
C++标准没有使用“线程安全”这样的术语,而是使用了更具体的语言。人类使用“线程安全”这样的术语,因为我们发现它们很有用。
线程安全函数的常见思想是,当调用时,假设没有其他人搞砸,它不会创建数据竞争。get_x是线程安全的;在所有条件相同的情况下,您可以从任意数量的线程调用它,并得到合理的结果。这是正确的,即使不能与set_x并发调用,因为这会导致数据竞争。但是,数据争用的原因是您调用了一个非线程安全函数:set_x。
将函数划分为“线程安全”或“非线程安全”的意义在于分配责备。如果您只调用“线程安全”函数,那么您的代码就是“线程安全”。如果您偏离了“线程安全”函数的边界,那么是您偏离了这些边界导致了数据竞争。
并发的get_x调用导致数据竞争并不是set_x的错。
至于get/set_y问题,如前所述,“线程安全”不是计算术语,也不是严格的标准术语。这是一个人类术语,是对计算现实的简化。
“线程安全”的规则基本上是,“您可以与任何其他线程安全函数同时调用任何线程安全函数”。如果不能同时调用get_y和set_y,那么它们就不是“线程安全”。
从严格的角度来看,描述这两个函数的准确方法是,set_y与同一对象上对set_y的其他调用同步,get_y与同一对象上对get_y的其他调用同步。事实上,我们也没有说它们是同步的,这告诉你你需要知道的是什么。
从简化的角度来看,set_y是“线程安全的”,而get_y则不是。但你也可以说get_y是“线程安全的”,而set_y则不是。这并不重要,因为这只是一种简化。
以及您是否声明get_y const并不是它“线程安全”的原因。萨特是说,如果你写了一个const函数,你的工作就是这样做,它是“线程安全”。因此,get_y之所以中断,是因为它不是以线程安全的方式编写的,因为它不能与其他线程安全函数一起调用线程。
发布于 2021-04-18 02:08:30
我还将附上您的以下声明:
如果一个函数不访问任何可以在没有由另一个函数进行内部同步的情况下修改的内存,则该函数是线程安全的。在我看来,这似乎是最一致的选择,但并不是经常使用的方式。
只要共享变量是原子的,并且正确地使用互斥来实现同步,我看不出上面的语句有什么问题。
https://stackoverflow.com/questions/67143880
复制相似问题