使用C ++进行线程安全并通过引用传递

时间:2012-01-03 06:32:23

标签: c++ thread-safety

我想确认我对线程的理解以及在C ++中通过引用传递。以下函数线程是否安全?

QString sA = "hello";
QString sB = "world";
bool someFlag = AreStringsEqual(sA,sB);

...

bool AreStringsEqual(QString const &stringA, QString const &stringB)
{
    if(stringA == stringB)
    {   return true;   }

    return false;
}

我认为线程安全的。如果有人能确认我的思考过程,或者告诉我我不知道我在说什么,我会喜欢它。

  • 进程内存中有两个sA和sB副本。在Thread1的堆栈上创建一个集合,在Thread2的堆栈上创建第二个集合。因为我们通过引用传递,所以每个线程在内存中只需要一组sA和sB来执行函数调用。

  • 如果我们通过值传递,那么在某个时间点,进程内存中最多可能有四个sA和sB副本(每个线程有两个集合),其中两个线程都在函数内交换处理器控制调用

  • 在任何情况下都不会共享内存,因此该函数是线程安全的。

很抱歉,如果这个问题非常简单,那么线程就会让我的脑子大吃一惊:)

的PRI

5 个答案:

答案 0 :(得分:3)

没有理由说两个线程不能保存对相同字符串的引用。

此函数是线程安全的,因为语句if(stringA == stringB)不是原子的。 首先,您从内存中获取stringA,然后才{@ 1}}。

让我们留下string B

你获取stringA == stringB == 2,然后有一个上下文切换,stringA和stringB都变为3.然后你获取stringA。您的函数将返回false(因为stringB),尽管2 != 3一直等于stringA

答案 1 :(得分:2)

您的问题在sAsB被宣布的位置有点模糊。听起来它们是在一个函数内声明的,在这种情况下,你要纠正每个线程都拥有它自己的sAsB版本。但是,如果它们在全球范围内宣布的奇怪机会,情况并非如此。如果我正确地理解了你的问题,你的意思是两者都是在本地范围内宣布的,所以你的第一点是正确的。出于同样的原因,你的第二点也是正确的。

但你的第三点是棘手的。在您的特定情况下,没有共享内存,因此您的程序是一个线程安全的"程序(不确定这是否是一个很好的方式来表达它)。但是,函数AreStringsEqual 是线程安全的。在将来的某个时刻,您(或其他人)可以将该函数与 共享的数据一起使用,并且该函数本身不会保护自己不受此用途的影响。

答案 2 :(得分:2)

除非QString指定operator== 线程安全,否则该函数线程安全。 AreStringsEqual的实现本身不会保护数据。

您正在通过此实现将线程安全的责任放在客户端上。客户端必须确保参数和参数的内部数据在AreStringsEqual时不会发生变异(例如,由另一个线程)。因此,他们可能会发现自己不必要的副本。必须如何实现这一点必须由QString的实施决定。即使std::string实施也有很大差异=)

对于并发上下文中的字符串,通常会在将字符串移动到并发上下文之前获取副本。如果真的需要共享,你需要一些东西来保护它(比如锁)。对于原始集合(例如std::stringstd::vector),您将希望避免在每次访问时锁定,因为它会破坏性能并且可能很容易失败。因此,如果必须共享非显式线程安全的对象,通常会复制或锁定。

因此,AreStringsEqual的实现不是线程安全的(再次,除非bool QString::operator==(const QString&) const保证是线程安全的。)

但是,AreStringsEqual用法

QString sA = "hello";
QString sB = "world";
bool someFlag = AreStringsEqual(sA,sB);

对于大多数字符串实现都没问题,因为参数及其数据对于线程是本地的。

答案 3 :(得分:1)

如果线程之间共享sA和sB,则该函数不是线程安全的。

很可能在一个线程中执行函数AreStringsEqual期间,另一个线程尝试修改sA或sB或两者的值,然后会出现Race条件。

虽然您的函数没有修改值,但函数外部的代码可以。

因此最好使用pass by value,因为该函数将在堆栈上具有本地副本 这保证是线程安全的

答案 4 :(得分:0)

首先,如果它们总是具有相同的值,那么为什么你需要两个相同字符串的副本并不清楚。

根据你描述的上下文,它可能是线程安全的,但只是查看它自己的函数,它不是线程安全的,因为在执行if条件时,字符串的值可能已经改变了。