Безопасно ли использовать в качестве функции-члена одного класса в разных потоках? - PullRequest
0 голосов
/ 11 февраля 2012

Например:

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 защищаться мьютексом или чем-то еще?Здесь нет условий гонки?

Ответы [ 5 ]

3 голосов
/ 11 февраля 2012

Это зависит от кода в методе. Если в методе нет гонок, это нормально. В вашем примере их нет, так как кода нет;)

В вашем примере, "а" может быть уничтожено до выхода из потоков (если пользователь работает быстро).

1 голос
/ 12 февраля 2012

Ответ зависит от класса.Если методы не имеют общего доступа к одним и тем же переменным экземпляра, синхронизация не требуется.Это связано с тем, что механизм вызова метода по своей сути поточно-ориентирован, поскольку не изменяет объект.Если они имеют общий доступ, вам нужна синхронизация.Возьмем, к примеру, этот класс:

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

private:
  int x;
};

Если нескольким потокам разрешено вызывать методы А одновременно, вам нужно защитить 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 ().Это лучшее из обоих миров за счет увеличения сложности.

Выбор между этими вариантами - дело вкуса и опыта.

1 голос
/ 11 февраля 2012

Вопрос довольно общий, и я считаю, что приведенный вами пример не соответствует вопросу.

В любом нетривиальном приложении да, вам нужно синхронизировать доступ к переменным экземпляра, если вы не можетегарантировать, что экземпляр класса никогда не будет доступен из разных потоков.

О методах и потоках;Локальные переменные в методе находятся в стеке и как таковые по своей природе поточно-ориентированы.Если метод обращается к переменным экземпляра, этот метод не является поточно-ориентированным.

0 голосов
/ 11 февраля 2012

Если ни run1(), ни run2() не изменяют переменную-член a или эта переменная никогда не используется впоследствии, тогда да, это безопасно.Более общее слово для него - без гражданства.

0 голосов
/ 11 февраля 2012

Только если в вашей работе заблокирован и синхронизирован мьютекс.

...