猪猪虾 发表于 2023-8-27 17:24:53

c++ 多线程文件存储问题

本帖最后由 猪猪虾 于 2023-8-27 17:37 编辑

(下面回复没有解决本质问题,大家别走)

我脑子已经转不动了,实在看不出来啥地方有问题了

有两个类,一个叫EventAction,另一个叫SteppingAction,一次EventAction的调用,会执行多次的SteppingAction的调用,总的会执行很多次的EventAction
我在EventAction类里面,每次EventAction类运行结束,我就对EventAction进行累加,并且加锁的方式判断当前是第几次EventAction,假设我有20次EventAction要执行,每5次的结果依次保存在一个新的txt文件夹里面,
当满足这个条件,我就EventAction里面重命名txt;

另一方面,在SteppingAction里面,我实时获取EventAction里面的txt的文件名字,然后将结果保存到新的txt里面

但是现在问题是,总是只有第一个默认的txt产生,其他txt在执行结束之后,都没有生成。我打印EventAction和SteppingAction里面的中间过程发现,txt名字的更改都是对的且传递也是对的,那么问题在哪呢

txt相关的主要在两个函数里面
EventAction.c 的 void EventAction::EndOfEventAction(const G4Event* aEvent)
以及 SteppingAction.c的void SteppingAction::UserSteppingAction(const G4Step* step)

//
//
/// \file EventAction.hh
namespace B1
{

    class RunAction;

    class EventAction : public G4UserEventAction
    {
    public:
      EventAction(RunAction* runAction);
      ~EventAction() override;

      void BeginOfEventAction(const G4Event* event) override;
      void EndOfEventAction(const G4Event* event) override;

      void AddEdep(G4int edep) { fEdep += edep; }

      void test();

      G4String Get_newFilename(){return filename_in_Event;};
    private:

      RunAction* fRunAction = nullptr;
      G4double   fEdep = 0.;//相当于全局变量,能量作加和,在AddEdep实现不断累加

      static std::mutex myLock; // 用于保护需要同步的资源
      static G4int TotalCount ;
      static G4int FileCount ;

      G4String filename_in_Event;
    };
}


//
/// \file EventAction.cc
/// \brief Implementation of the B1::EventAction class

namespace B1
{

    std::mutex EventAction::myLock;
    G4int EventAction::TotalCount = 0;
    G4int EventAction::FileCount = 0;

    EventAction::EventAction(RunAction* runAction)
            : fRunAction(runAction)
    {

    }


    EventAction::~EventAction()
    {}

    void EventAction::BeginOfEventAction(const G4Event*)
    {
      fEdep = 0.;
    }

    void EventAction::EndOfEventAction(const G4Event* aEvent)
    {
      std::lock_guard<std::mutex> lock(myLock);// 加锁

      TotalCount ++;
      filename_in_Event = "NULL";
      if(TotalCount %10000000 ==0)
      {
            FileCount ++;
            filename_in_Event = "DataOfRun_" + std::to_string(FileCount) + ".txt";
//            G4cout<< "*!!!!!!!!!!!!!!!!!!******* EndOfEventAction ,TotalCount : "<< TotalCount <<
//                  ",filename_in_Event :"<<filename_in_Event<<G4endl;
      }

   //   test();
    }

    void EventAction::test()
    {
      G4String temp = "NULL";
      temp = Get_newFilename();
      if(temp == "NULL")
      {
            G4cout<< "*!!!!!!!!!!!!!!!!!!******* in EventAction :NULL "<<G4endl;
      }
      else
      {
            G4cout<< "*!!!!!!!!!!!!!!!!!!******* in EventAction : "<< temp<<G4endl;
      }

    }

}


//
/// \file SteppingAction.hh
using namespace std;
namespace B1
{

    class EventAction;

    class SteppingAction : public G4UserSteppingAction
    {
    public:
      SteppingAction(EventAction* eventAction);
      ~SteppingAction() override;
      void UserSteppingAction(const G4Step*) override;
    private:
      EventAction* fEventAction = nullptr;
      G4LogicalVolume* fScoringVolume = nullptr;

      G4String filename;
    };

}


//
/// \file SteppingAction.cc
/// \brief Implementation of the B1::SteppingAction class
namespace B1
{
    SteppingAction::SteppingAction(EventAction* eventAction)
            : fEventAction(eventAction)
    {
      filename = "DataOfRun_0.txt";
    }

    SteppingAction::~SteppingAction()
    {}

    void SteppingAction::UserSteppingAction(const G4Step* step) {
      G4String volumeName = step->GetPreStepPoint()->GetPhysicalVolume()->GetName();
      G4String ParticleName = step->GetTrack()->GetDynamicParticle()->GetParticleDefinition()->GetParticleName();

      G4String Newfilename = fEventAction->Get_newFilename();
//      G4cout<< "*!!!!!!!!!!!!!!!!!!******* Newfilename: "<< Newfilename <<G4endl;
//      G4cout<<"#############gaga : volumeName " << volumeName <<G4endl;
//      if (ParticleName == "gamma" && volumeName == "DetectorArray")
      if (volumeName == "DetectorArray")
      {
            G4int copyNo = step->GetPreStepPoint()->GetTouchableHandle()->GetCopyNumber(0);
            G4double edep = step->GetTotalEnergyDeposit();
         
            if(Newfilename!= "NULL")
            {
                ofstream outf;
                outf.open(Newfilename,ios::app);
                outf<< copyNo << ' ' << edep << ' ';
                outf.close();
            }
            else
            {
//                G4cout<< "*!!!!!!!!!!!!!!!!!!******* in stepAction :NULL , filename = " << filename <<G4endl;
                ofstream outf;
                outf.open(filename,ios::app);
                outf<< copyNo << ' ' << edep << ' ';
                outf.close();
            }
      }
    }


}

陶远航 发表于 2023-8-27 17:25:31

根据你提供的代码,我看到你使用了互斥锁来保护资源的访问,但是在文件操作部分存在一些问题。

首先,在EventAction类中,你使用Get_newFilename()方法获取当前的文件名。然而,在BeginOfEventAction和EndOfEventAction函数中都调用了test()方法,这意味着每次事件开始和结束时都会调用Get_newFilename()方法,导致在同一个事件中可能多次获取相同的文件名。

其次,在SteppingAction类中,在写入文件之前,你也通过fEventAction->Get_newFilename()方法获取文件名,并将其赋值给Newfilename。但是,你并没有在调用ofstream对象的open函数之前检查Newfilename是否为"NULL",这可能导致打开的文件名为空或错误。你应该在打开文件之前检查文件名是否为空。

另外,你在SteppingAction类的构造函数中将filename初始化为"DataOfRun_0.txt",但是在代码中并没有修改filename的值。因此,在执行保存数据到文件的操作时,始终使用的是默认的文件名。

最后,你可以尝试给文件操作的代码添加一些debug信息,例如打印文件名和相关的提示信息,以便更好地排查问题所在。

希望以上解释和建议能够帮助你找到问题所在并解决它。
如果问题已经解决,请设置最佳答案

isdkz 发表于 2023-8-27 17:25:55

问题的原因是在EventAction类中,每次EventAction类运行结束后,你使用锁来判断当前是第几次EventAction,并根据条件对文件进行重命名。然而,在SteppingAction类中,你实时获取EventAction类中的文件名,并将结果保存到新的文件中。但是,你在SteppingAction类中使用的文件名始终是初始化时的默认文件名,而不是EventAction类中实时更新的文件名。

解决这个问题的方法是,在SteppingAction类中,你应该使用EventAction类的成员函数Get_newFilename()来获取实时更新的文件名。你可以在SteppingAction类的构造函数中将EventAction类的指针作为参数传递,并将其存储在SteppingAction类的成员变量fEventAction中。然后,在UserSteppingAction函数中,使用fEventAction->Get_newFilename()来获取实时更新的文件名。

以下是修改后的代码示例:

// SteppingAction.hh
using namespace std;

namespace B1
{
    class EventAction;

    class SteppingAction : public G4UserSteppingAction
    {
    public:
      SteppingAction(EventAction* eventAction);
      ~SteppingAction() override;
      void UserSteppingAction(const G4Step*) override;
    private:
      EventAction* fEventAction = nullptr;
      G4LogicalVolume* fScoringVolume = nullptr;

      G4String filename;
    };
}

// SteppingAction.cc
namespace B1
{
    SteppingAction::SteppingAction(EventAction* eventAction)
      : fEventAction(eventAction)
    {
      filename = "DataOfRun_0.txt";
    }

    SteppingAction::~SteppingAction()
    {}

    void SteppingAction::UserSteppingAction(const G4Step* step)
    {
      G4String volumeName = step->GetPreStepPoint()->GetPhysicalVolume()->GetName();
      G4String ParticleName = step->GetTrack()->GetDynamicParticle()->GetParticleDefinition()->GetParticleName();

      G4String Newfilename = fEventAction->Get_newFilename();
      // 使用实时更新的文件名Newfilename
      if (volumeName == "DetectorArray")
      {
            G4int copyNo = step->GetPreStepPoint()->GetTouchableHandle()->GetCopyNumber(0);
            G4double edep = step->GetTotalEnergyDeposit();

            if (Newfilename != "NULL")
            {
                ofstream outf;
                outf.open(Newfilename, ios::app);
                outf << copyNo << ' ' << edep << ' ';
                outf.close();
            }
            else
            {
                ofstream outf;
                outf.open(filename, ios::app);
                outf << copyNo << ' ' << edep << ' ';
                outf.close();
            }
      }
    }
}


通过这种方式,你将能够在SteppingAction类中使用实时更新的文件名,并将结果保存到正确的文件中。

猪猪虾 发表于 2023-8-27 17:31:30

isdkz 发表于 2023-8-27 17:25
问题的原因是在EventAction类中,每次EventAction类运行结束后,你使用锁来判断当前是第几次EventAction, ...

虽然初始化是固定的文件名,但是在void SteppingAction::UserSteppingAction(const G4Step* step)函数里面,
我做了if判断的,先判断传进来的文件名是不是被更新了,如果被更新了,我就优先使用新的文件名,我的逻辑是没有问题的对吧

sfqxx 发表于 2023-8-27 17:47:32

领鱼币,再回答
页: [1]
查看完整版本: c++ 多线程文件存储问题