在不同线程中用作一个类的成员函数是否安全?

发布于 2025-01-04 19:09:49 字数 508 浏览 4 评论 0原文

例如:

struct A {    
void run1() {}
void run2() {}    
};

int main()
{
  A a;

  thread t1(bind(&A::run1, ref(a)));
  thread t2(bind(&A::run2, ref(a)));

  // not joinable thread!

  int i;
  std::cin >> i;
}

请查看此示例 http://developer.gnome.org/ glibmm/unstable/thread_2thread_8cc-example.html

a 对象是否应该受到互斥体或其他东西的保护?这里没有竞争条件吗?

For example:

struct A {    
void run1() {}
void run2() {}    
};

int main()
{
  A a;

  thread t1(bind(&A::run1, ref(a)));
  thread t2(bind(&A::run2, ref(a)));

  // not joinable thread!

  int i;
  std::cin >> i;
}

And please look at this example http://developer.gnome.org/glibmm/unstable/thread_2thread_8cc-example.html

Does the a object should be protected by mutex or something else? Is there no race condition here?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

梦年海沫深 2025-01-11 19:09:49

这取决于方法中的代码。如果该方法中没有竞赛,那就没问题。您的示例中没有,因为没有代码;)

在您的示例中,“a”可能会在线程退出之前被销毁(如果用户速度很快)。

It depends on the code in the method. If there are no races in the method it is fine. There are non in your example since there is no code ;)

In your example, "a" might get destroyed before the threads exit (if the user is fast).

把时间冻结 2025-01-11 19:09:49

答案取决于班级。如果这些方法不共享对相同实例变量的访问,则不需要同步。这是因为方法调用机制本质上是线程安全的,因为它不会修改对象。如果他们共享访问权限,您就需要同步。以此类为例:

class A
{
public:
  void inc () { x++; }
  void dec () { x--; }

private:
  int x;
};

如果允许多个线程同时调用A的方法,则需要用互斥锁来保护x。有几种可能的策略。一是使类成为线程安全的。看起来像这样:

class A
{
  public:
  void inc () {
    m.lock();
    x++;
    m.unlock();
  }

  void dec () {
    m.lock();
    x--;
    m.unlock();
  }

private:
  int x;
  mutex m;
};

这里的优点是调用者不必担心同步。缺点是如果仅从一个线程调用该类,则会降低性能。如果您需要保证一个线程可以连续调用多个方法而不受另一个线程的干扰,那么您还会遇到问题。在这种情况下,调用线程需要在使用该类之前查看该类。它看起来像这样:

class A
{
  public:
  void lock () { m.lock(); }
  void unlock () { m.unlock(); }
  void inc () { x++; }
  void dec () { x--; }

private:
  int x;
  mutex m;
};

然后调用者必须将方法调用包装在 A::lock()/A::unlock() 对中。如果您需要使用未考虑到线程安全性而编写的类,则需要在对象外部创建一个互斥锁,并像前面的示例一样使用它。或者您可以创建一个线程安全的包装器。当然,缺点是这很容易出错。

请注意,您还可以同时提供锁定和解锁访问:

class A
    {
      public:
      void lock () { m.lock(); }
      void unlock () { m.unlock(); }
      void inc_unlocked () { x++; }
      void dec_unlocked () { x--; }
      void inc () { m.lock(); inc_unlocked(); m.unlock(); }
      void dec () { m.lock(); dec_unlocked(); m.unlock(); }

    private:
      int x;
      mutex m;
    };

这样,如果该类在单线程应用程序中使用,则可以使用解锁版本来提高性能,否则您可以使用锁定版本或包装在 lock()/unlock( 中的解锁版本) 来电。这是两全其美的方法,但代价是复杂性增加。

如何在这些选项之间进行选择取决于品味和经验。

The answer depends on the class. If the methods don't share access to the same instance variables you don't need synchronization. That's because the method call mechanism is inherently thread-safe as it doesn't modify the object. If they do share access, you need synchronization. Take this class for example:

class A
{
public:
  void inc () { x++; }
  void dec () { x--; }

private:
  int x;
};

If several threads are allowed to call A's methods at the same time, you need to protect the x with a mutex. There are several possible strategies. One is to make the class thread-safe. That would look like this:

class A
{
  public:
  void inc () {
    m.lock();
    x++;
    m.unlock();
  }

  void dec () {
    m.lock();
    x--;
    m.unlock();
  }

private:
  int x;
  mutex m;
};

The advantage here is that callers don't have to worry about synchronization. The downside is the performance penalty if the class is only ever called from one thread. You also have an issue if you need to guarantee that a thread can call several methods in a row without interference from another thread. In this case the calling thread need to look the class before using it. It would look like this:

class A
{
  public:
  void lock () { m.lock(); }
  void unlock () { m.unlock(); }
  void inc () { x++; }
  void dec () { x--; }

private:
  int x;
  mutex m;
};

The callers must then wrap method calls in a A::lock()/A::unlock() pair. If you need to use a class that was not written with thread-safety in mind you need to create a mutex outside the object and use it as in the previous example. Or you can create a thread-safe wrapper. The downside of course is that this is error-prone.

Note that you can also offer both locked and unlocked access:

class A
    {
      public:
      void lock () { m.lock(); }
      void unlock () { m.unlock(); }
      void inc_unlocked () { x++; }
      void dec_unlocked () { x--; }
      void inc () { m.lock(); inc_unlocked(); m.unlock(); }
      void dec () { m.lock(); dec_unlocked(); m.unlock(); }

    private:
      int x;
      mutex m;
    };

This way if the class is used in a single thread application you use the unlocked versions for performance otherwise you use either the locked versions or the unlocked versions wrapped in lock()/unlock() calls. That is the best of both worlds, at the cost of an increase in complexity.

How to choose between these options is a matter of taste and experience.

黑白记忆 2025-01-11 19:09:49

这个问题很笼统,我觉得你举的例子与问题不符。

在任何重要的应用程序中,是的,您确实需要同步对实例变量的访问,除非您可以保证永远不会从不同的线程访问该类的实例。

关于方法和线程;方法中的局部变量驻留在堆栈上,因此本质上是线程安全的。如果该方法访问实例变量,则该方法本质上不是线程安全的。

The question is fairly general, and I feel the example you give doesn't match the question.

In any non-trivial application then yes, you do need to synchronize access to instance variables unless you can guarantee that an instance of the class will never be accessed from different threads.

About methods and threads; local variables in a method reside on the stack and as such are inherently thread-safe. If the method accesses instance variables that method is not inherently thread-safe.

白色秋天 2025-01-11 19:09:49

仅当您的工作中有一些互斥锁需要锁定和同步时。

Only if there are some mutex to locked and synchronized in your working.

你的往事 2025-01-11 19:09:49

如果 run1()run2() 都没有更改 a 的成员变量,或者该变量之后从未使用过,那么是的,它是安全的。更通用的词是无状态。

If neither run1() nor run2() changes a member variable of a or that variable is never used afterwards, then yes, it is safe. A more generic word for it is stateless.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文