鱼C论坛

 找回密码
 立即注册
查看: 554|回复: 4

[已解决]c++ 多线程文件存储问题

[复制链接]
发表于 2023-8-27 17:24:53 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 猪猪虾 于 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: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类中使用实时更新的文件名,并将结果保存到正确的文件中。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2023-8-27 17:25:31 | 显示全部楼层
根据你提供的代码,我看到你使用了互斥锁来保护资源的访问,但是在文件操作部分存在一些问题。

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

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

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

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

希望以上解释和建议能够帮助你找到问题所在并解决它。
如果问题已经解决,请设置最佳答案
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 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类中使用实时更新的文件名,并将结果保存到正确的文件中。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

虽然初始化是固定的文件名,但是在void SteppingAction::UserSteppingAction(const G4Step* step)函数里面,
我做了if判断的,先判断传进来的文件名是不是被更新了,如果被更新了,我就优先使用新的文件名,我的逻辑是没有问题的对吧
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-8-27 17:47:32 | 显示全部楼层

回帖奖励 +1 鱼币

领鱼币,再回答
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-6-17 05:39

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表