C++ 仍然具有boost::mutex的竞争条件

C++ 仍然具有boost::mutex的竞争条件,c++,boost,mutex,boost-thread,C++,Boost,Mutex,Boost Thread,我正在尝试一个示例,它会导致种族条件应用互斥。然而,即使使用互斥,这种情况仍然会发生。发生了什么?这是我的密码: #include <iostream> #include <boost/thread.hpp> #include <vector> using namespace std; class Soldier { private: boost::thread m_Thread; public: static int count , moneySpe

我正在尝试一个示例,它会导致种族条件应用互斥。然而,即使使用互斥,这种情况仍然会发生。发生了什么?这是我的密码:

#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';
}
#包括
#包括
#包括
使用名称空间std;
班兵
{
私人:
boost::线程m_线程;
公众:
静态整数计数,moneyspend;
静态增强::互斥soldierMutex;
士兵({}
无效开始(整数成本)
{
m_Thread=boost::Thread(&Soldier::process,this,cost);
}
无效流程(内部成本)
{
{
boost::mutex::作用域锁定(soldierMutex);
//soldierMutex.lock();
int tmp=计数;
++tmp;
计数=tmp;
tmp=花费的金钱;
tmp+=成本;
支出金额=tmp;
//soldierMutex.unlock();
}
}  
void join()
{
m_Thread.join();
}
};
int士兵::计数,士兵::花费的金钱;
增强::互斥士兵::士兵mutex;
int main()
{
士兵s1、s2、s3;
s1.启动(20);
s2.启动(30);
s3.启动(40);
s1.join();
s2.join();
s3.join();
对于(int i=0;i<100;++i)
{
士兵;
s、 启动(30);
}

cout看起来您没有等待循环中启动的线程完成。请将循环更改为:

 for (int i = 0; i < 100; ++i)
 {
   Soldier s;
   s.start(30);
   s.join();
 }
for(int i=0;i<100;++i)
{
士兵;
s、 启动(30);
s、 join();
}
编辑以进一步解释


您看到的问题是打印出来的值是错误的,因此您假设线程中存在争用条件。争用事实上是在您打印值时发生的,而不是所有线程都有机会执行这些值,基于此和您之前的帖子(您似乎还没有阅读所有答案)。您正在寻找某种形式的同步点,以防止main()线程退出应用程序(因为当主线程退出应用程序时,所有子线程都会死亡)

这就是为什么要一直调用join(),以防止main()线程退出,直到线程退出为止。由于您的使用,虽然线程循环不是并行的,每个线程都是按顺序运行到完成的(因此使用线程没有实际意义)

注意:join()与Java中的类似,等待线程完成。它不会启动线程。

快速浏览一下boost文档,就会发现您正在寻找的是一个线程组,它允许您在退出之前等待组中的所有线程完成

//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();
}
//没有编译器,因此未经测试。
//但它应该是这样的。
//注2:我很少使用boost::threads。
int main()
{
boost::线程组;
boost::ptr_向量线程;
for(int循环=0;循环<100;++loop)
{
//创建一个对象。
//使用函数使其启动。将线程存储在向量中
threads.push_back(新的boost::thread());
//将线程添加到组中。
group.add(threads.back());
}
//确保在所有线程完成之前,main不会退出。
组。加入所有人();
}
如果我们回到您的示例并改装您的士兵类:

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';
}
intmain()
{
线棒;
//使所有士兵成为一个小组的一部分。
//启动线程时,请使线程加入组。
士兵s1(指挥棒);
士兵s2(巴塔利翁);
士兵s3(巴塔利翁);
s1.启动(20);
s2.启动(30);
s3.启动(40);
//在厕所外创造100名士兵
性病:病媒;
LOTSOF士兵。保留(100);//防止循环中的重新分配。
//因为您正在使用我们需要的对象
//防止在线程启动后复制它们。
对于(int i=0;i<100;++i)
{
很多士兵。推回(焊锡(巴塔利恩));
LOTSOF.back().start(30);
}
//在线程仍在运行时打印值
//注意,你可以在任何线程之前到达这里。

出于好奇…你为什么不直接做
count++
moneywasted+=cost;
?在那个块中
tmp
的目的是什么?你应该摆脱它。你为什么不等待循环中开始的线程完成呢?@littleadv:我想你发现了他的bug…也许你应该给出一个答案:-)@iammillind:这就是低级别的情况。复制到寄存器,增加它,然后复制回包含变量的内存单元。我只想演示这个过程。此外,我想有更多的代码让竞争条件发生。这是有意的。注意,这会序列化线程。要并行运行线程,可以分配<代码>士兵
s在堆上,并有第二个循环来加入它们,但这并不重要,因为锁无论如何都会序列化它们。等等,互斥的目的不是为了防止竞争条件吗?如果是这样,那么就不应该有任何加入。你能解释一下为什么每次创建boost::thread时我都要加入吗?我记得在Java,加入是可选的。这是必须的吗?据我所知,在没有加入的情况下,线程仍在运行。现在我想要类似于Java的东西,我可以创建一个对象或o lock对象来锁定代码区域,因此线程将只对该代码块按顺序进行处理。加入当然是可选的,并且代码受您的保护x不会并行运行。但等待线程完成与不并行执行某些代码不同。@Amumu-我在答案中添加了一部分来解释您不清楚的地方。