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();
}
}
}
}
根据你提供的代码,我看到你使用了互斥锁来保护资源的访问,但是在文件操作部分存在一些问题。
首先,在EventAction类中,你使用Get_newFilename()方法获取当前的文件名。然而,在BeginOfEventAction和EndOfEventAction函数中都调用了test()方法,这意味着每次事件开始和结束时都会调用Get_newFilename()方法,导致在同一个事件中可能多次获取相同的文件名。
其次,在SteppingAction类中,在写入文件之前,你也通过fEventAction->Get_newFilename()方法获取文件名,并将其赋值给Newfilename。但是,你并没有在调用ofstream对象的open函数之前检查Newfilename是否为"NULL",这可能导致打开的文件名为空或错误。你应该在打开文件之前检查文件名是否为空。
另外,你在SteppingAction类的构造函数中将filename初始化为"DataOfRun_0.txt",但是在代码中并没有修改filename的值。因此,在执行保存数据到文件的操作时,始终使用的是默认的文件名。
最后,你可以尝试给文件操作的代码添加一些debug信息,例如打印文件名和相关的提示信息,以便更好地排查问题所在。
希望以上解释和建议能够帮助你找到问题所在并解决它。
如果问题已经解决,请设置最佳答案 问题的原因是在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类中使用实时更新的文件名,并将结果保存到正确的文件中。 isdkz 发表于 2023-8-27 17:25
问题的原因是在EventAction类中,每次EventAction类运行结束后,你使用锁来判断当前是第几次EventAction, ...
虽然初始化是固定的文件名,但是在void SteppingAction::UserSteppingAction(const G4Step* step)函数里面,
我做了if判断的,先判断传进来的文件名是不是被更新了,如果被更新了,我就优先使用新的文件名,我的逻辑是没有问题的对吧 领鱼币,再回答
页:
[1]