Все еще в состоянии гонки с бустом :: mutex - PullRequest
2 голосов
/ 05 июня 2011

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

#include <iostream>
#include <boost/thread.hpp>
#include <vector>
using namespace std;
class Soldier
{
private:
  boost::thread m_Thread;
public:
  static int count , moneySpent;
  static boost::mutex soldierMutex;   
  Soldier(){}
  void start(int cost)
  {
    m_Thread = boost::thread(&Soldier::process, this,cost);
  }

  void process(int cost)
  {
    {
    boost::mutex::scoped_lock lock(soldierMutex);
    //soldierMutex.lock();
    int tmp = count;
    ++tmp;
    count = tmp;
    tmp = moneySpent;
    tmp += cost;
    moneySpent = tmp;  
   // soldierMutex.unlock();
    }
  }  

  void join()
  {
    m_Thread.join();
  }
};

int Soldier::count, Soldier::moneySpent;
boost::mutex Soldier::soldierMutex;

int main()
{
  Soldier s1,s2,s3;
  s1.start(20);
  s2.start(30);
  s3.start(40);
  s1.join();
  s2.join();
  s3.join();
  for (int i = 0; i < 100; ++i)
    {
      Soldier s;
      s.start(30);
    }
  cout << "Total soldier: " << Soldier::count << '\n';
  cout << "Money spent: " << Soldier::moneySpent << '\n';
}

Ответы [ 2 ]

7 голосов
/ 05 июня 2011

Похоже, вы не дожидаетесь окончания потоков, запущенных в цикле. Измените цикл на:

 for (int i = 0; i < 100; ++i)
 {
   Soldier s;
   s.start(30);
   s.join();
 }

изменить, чтобы объяснить дальше

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

1 голос
/ 05 июня 2011

Исходя из этого и вашего предыдущего поста (если кажется, что вы еще не прочитали все ответы). То, что вам нужно, это какая-то форма точки синхронизации, чтобы предотвратить выход основного потока () из приложения (поскольку, когда основной поток выходит из приложения, все дочерние потоки умирают).

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

Примечание: join (), как в Java, ожидает завершения потока. Не запускается поток.

Беглый взгляд на документацию по надстройке показывает, что вам нужна группа потоков, которая позволит вам дождаться завершения всех потоков в группе перед выходом.

//No compiler so this is untested.
// But it should look something like this.
// Note 2: I have not used boost::threads much.
int main()
{
    boost::thread_group               group;

    boost::ptr_vector<boost::thread>  threads;

    for(int loop = 0; loop < 100; ++loop)
    {
        // Create an object.
        // With the function to make it start. Store the thread in a vector
        threads.push_back(new boost::thread(<Function To Call>));

        // Add the thread to the group.
        group.add(threads.back());
    }

    // Make sure main does not exit before all the threads have completed.
    group.join_all();
}

Если мы вернемся к вашему примеру и модифицируем ваш класс солдат:

int main()
{
  boost::thread batallion;

  // Make all the soldiers part of a group.
  // When you start the thread make the thread join the group.
  Soldier s1(batallion);
  Soldier s2(batallion);
  Soldier s3(batallion);

  s1.start(20);
  s2.start(30);
  s3.start(40);

  // Create 100 soldiers outside the loo
  std::vector<Soldier>  lotsOfSoldiers;
  lotsOfSoldiers.reserve(100);  // to prevent reallocation in the loop.
                                // Because you are using objects we need to 
                                // prevent copying of them after the thread starts.

  for (int i = 0; i < 100; ++i)
  {
      lotsOfSoldiers.push_back(Solder(batallion));
      lotsOfSoldiers.back().start(30);
  }

  // Print out values while threads are still running
  // Note you may get here before any thread.
  cout << "Total soldier: " << Soldier::count << '\n';
  cout << "Money spent: " << Soldier::moneySpent << '\n';

  batallion.join_all();

  // Print out values when all threads are finished.
  cout << "Total soldier: " << Soldier::count << '\n';
  cout << "Money spent: " << Soldier::moneySpent << '\n';
}
...