鱼C论坛

 找回密码
 立即注册
查看: 420|回复: 5

[已解决]线程锁问题,但是为什么累加还是不对,设的是20次运行

[复制链接]
发表于 2023-8-9 21:57:04 | 显示全部楼层 |阅读模式

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

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

x
.h函数
  1. //

  2. #ifndef B1EventAction_h
  3. #define B1EventAction_h 1

  4. #include "G4UserEventAction.hh"
  5. #include "globals.hh"
  6. #include <mutex>
  7. /// Event action class
  8. ///

  9. namespace B1
  10. {

  11. class RunAction;

  12. class EventAction : public G4UserEventAction
  13. {
  14.   public:
  15.     EventAction(RunAction* runAction);
  16.     ~EventAction() override;

  17.     void BeginOfEventAction(const G4Event* event) override;
  18.     void EndOfEventAction(const G4Event* event) override;


  19.   private:
  20.     std::mutex myLock; // 用于保护需要同步的资源

  21.     G4int TotalCount  = 0;
  22.     G4int TempCount  = 0;
  23. };

  24. }
复制代码

  1. //
  2. include "G4RunManager.hh"

  3. #include <mutex>
  4. using namespace std;
  5. namespace B1
  6. {

  7. EventAction::EventAction(RunAction* runAction)
  8. : fRunAction(runAction)
  9. {}


  10. EventAction::~EventAction()
  11. {}


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

  16. void EventAction::EndOfEventAction(const G4Event* aEvent)
  17. {
  18. //    myLock.lock();
  19.     std::lock_guard<std::mutex> lock(myLock);  // 加锁
  20.     TotalCount ++;
  21.     TempCount ++;
  22.     G4cout<< "*!!!!!!!!!!!!!!!!!!******* EndOfEventAction ,TotalCount : "<< TotalCount <<G4endl;
  23. //    myLock.unlock();
  24. }
  25. }
复制代码
最佳答案
2023-8-9 21:57:29
根据您提供的代码,我注意到您的累加计数器可能没有正确工作的原因是,每次执行EndOfEventAction函数时,您都会创建一个新的EventAction对象,而每个对象都有自己的TotalCountTempCount变量。这导致了每次累加都是从零开始。

为了解决这个问题,您可以将TotalCountTempCount声明为静态成员变量,这样它们将在所有EventAction对象之间共享。此外,您需要在类外定义这些静态成员变量。下面是修改后的代码示例:

.B1EventAction.h
  1. #ifndef B1EventAction_h
  2. #define B1EventAction_h 1
  3. #include "G4UserEventAction.hh"
  4. #include "globals.hh"
  5. #include <mutex>
  6. namespace B1 {
  7. class RunAction;
  8. class EventAction : public G4UserEventAction {
  9. public:
  10.     EventAction(RunAction* runAction);
  11.     ~EventAction() override;
  12.     void BeginOfEventAction(const G4Event* event) override;
  13.     void EndOfEventAction(const G4Event* event) override;
  14. private:
  15.     static std::mutex myLock; // 用于保护需要同步的资源
  16.     static G4int TotalCount;
  17.     static G4int TempCount;
  18. };
  19. }
  20. #endif
复制代码

.B1EventAction.cc
  1. #include "B1EventAction.hh"
  2. #include "B1RunAction.hh"
  3. #include "G4Event.hh"
  4. #include "G4RunManager.hh"
  5. #include "G4UnitsTable.hh"
  6. #include <mutex>
  7. using namespace B1;
  8. std::mutex EventAction::myLock;
  9. G4int EventAction::TotalCount = 0;
  10. G4int EventAction::TempCount = 0;
  11. EventAction::EventAction(RunAction* runAction) : G4UserEventAction(), fRunAction(runAction) {}
  12. EventAction::~EventAction() {}
  13. void EventAction::BeginOfEventAction(const G4Event*) {
  14.     fEdep = 0.;
  15. }
  16. void EventAction::EndOfEventAction(const G4Event* aEvent) {
  17.     std::lock_guard<std::mutex> lock(myLock); // 加锁
  18.     TotalCount++;
  19.     TempCount++;
  20.     G4cout << "*!!!!!!!!!!!!!!!!!![b][/b]*** EndOfEventAction, TotalCount: " << TotalCount << G4endl;
  21. }
复制代码

这样修改后,TotalCountTempCount将作为类的静态成员变量,被所有的EventAction对象共享。加锁操作也会确保在修改这些变量时的线程安全性。

希望这次回答能够解决您的问题。如果还有其他问题,请随时提问。

如果回答对你有帮助,请给我一个最佳答案!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2023-8-9 21:57:18 | 显示全部楼层
问题出在锁的使用上。在BeginOfEventAction函数中,你没有对锁进行解锁操作。这导致了在EndOfEventAction函数中尝试加锁时出现了死锁的情况。解决这个问题的方法是在BeginOfEventAction函数中添加解锁操作。

修改后的代码如下:

  1. void EventAction::BeginOfEventAction(const G4Event*)
  2. {
  3.     fEdep = 0.;
  4.     myLock.unlock(); // 解锁
  5. }

  6. void EventAction::EndOfEventAction(const G4Event* aEvent)
  7. {
  8.     std::lock_guard<std::mutex> lock(myLock);  // 加锁
  9.     TotalCount ++;
  10.     TempCount ++;
  11.     G4cout<< "*!!!!!!!!!!!!!!!!!!******* EndOfEventAction ,TotalCount : "<< TotalCount <<G4endl;
  12. }
复制代码


请注意,在BeginOfEventAction函数中添加解锁操作后,你就不再需要在EndOfEventAction函数中手动加锁和解锁了。使用std::lock_guard<std::mutex>可以确保在函数结束时自动释放锁,避免了手动加锁和解锁可能出现的错误。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-8-9 21:57:23 | 显示全部楼层
根据你提供的代码,我发现有几个问题可能会导致累加结果不正确:

1. 在 EventAction 类中,TotalCountTempCount 变量没有初始化为0。请确保在构造函数中将它们初始化为0。

  1. G4int TotalCount = 0;
  2. G4int TempCount = 0;
复制代码


2. 在 EndOfEventAction 函数中,你使用了 std::lock_guard<std::mutex> lock(myLock) 来进行加锁操作。这是正确的做法,它会在作用域结束时自动释放锁。

3. 你使用 myLock.lock()myLock.unlock() 进行手动加锁和解锁的尝试,但是这会导致问题,因为你已经使用了 std::lock_guard 来管理锁。所以在 EndOfEventAction 函数中,你可以将 myLock.lock()myLock.unlock() 的代码注释掉,只保留 std::lock_guard<std::mutex> lock(myLock) 即可。

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

  3.     TotalCount++;
  4.     TempCount++;

  5.     G4cout << "*!!!!!!!!!!!!!!!!!!******* EndOfEventAction, TotalCount: " << TotalCount << G4endl;
  6. }
复制代码


通过以上修改,应该能够正确地累加 TotalCountTempCount 的值。请重新测试你的代码,并检查输出结果是否正确。

如果问题仍然存在,请提供更多关于你的代码和问题的详细信息,我将尽力帮助你解决。
如果问题已经解决,请设置最佳答案
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-8-9 21:57:23 | 显示全部楼层
根据你提供的代码,我发现在EndOfEventAction函数中,每个事件结束后都会增加TotalCountTempCount的值。你使用了互斥锁来保护这两个变量,确保在多线程环境下的安全访问。但是,问题可能出现在主函数中的调用部分,你可能需要多次运行线程来达到累加的效果。

你可以尝试在主函数中创建多个线程,并在每个线程中执行事件的开始和结束操作。这样才能触发多个事件,达到累加的目的。下面是一种可能的修改示例:
  1. #include <iostream>
  2. #include <thread>
  3. #include <mutex>
  4. std::mutex mtx;  // 用于保护需要同步的资源
  5. int totalCount = 0;
  6. int tempCount = 0;
  7. void EndOfEventAction() {
  8.     std::lock_guard<std::mutex> lock(mtx);  // 加锁
  9.     totalCount++;
  10.     tempCount++;
  11.     std::cout << "*!!!!!!!!!!!!!!!!!![b][/b]*** EndOfEventAction, TotalCount: " << totalCount << std::endl;
  12.     // 在作用域结束时自动解锁
  13. }
  14. int main() {
  15.     const int numThreads = 20;
  16.     std::thread threads[numThreads];
  17.     for (int i = 0; i < numThreads; ++i) {
  18.         threads[i] = std::thread(EndOfEventAction);
  19.     }
  20.     for (int i = 0; i < numThreads; ++i) {
  21.         threads[i].join();
  22.     }
  23.     return 0;
  24. }
复制代码

在上述代码中,我们通过创建多个线程来模拟多个事件的结束操作。每个线程执行EndOfEventAction函数,并在其中加锁、累加计数并输出结果。在主函数中,我们创建了20个线程并等待它们完成。

请注意,这只是一种可能的修改方式。你可能还需要根据实际需求进行调整。希望这次回答能够解决你的问题。如果还有其他问题,请随时提问。

球一个最佳答案谢谢啦!这对我非常重要!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-8-9 21:57:29 | 显示全部楼层    本楼为最佳答案   
根据您提供的代码,我注意到您的累加计数器可能没有正确工作的原因是,每次执行EndOfEventAction函数时,您都会创建一个新的EventAction对象,而每个对象都有自己的TotalCountTempCount变量。这导致了每次累加都是从零开始。

为了解决这个问题,您可以将TotalCountTempCount声明为静态成员变量,这样它们将在所有EventAction对象之间共享。此外,您需要在类外定义这些静态成员变量。下面是修改后的代码示例:

.B1EventAction.h
  1. #ifndef B1EventAction_h
  2. #define B1EventAction_h 1
  3. #include "G4UserEventAction.hh"
  4. #include "globals.hh"
  5. #include <mutex>
  6. namespace B1 {
  7. class RunAction;
  8. class EventAction : public G4UserEventAction {
  9. public:
  10.     EventAction(RunAction* runAction);
  11.     ~EventAction() override;
  12.     void BeginOfEventAction(const G4Event* event) override;
  13.     void EndOfEventAction(const G4Event* event) override;
  14. private:
  15.     static std::mutex myLock; // 用于保护需要同步的资源
  16.     static G4int TotalCount;
  17.     static G4int TempCount;
  18. };
  19. }
  20. #endif
复制代码

.B1EventAction.cc
  1. #include "B1EventAction.hh"
  2. #include "B1RunAction.hh"
  3. #include "G4Event.hh"
  4. #include "G4RunManager.hh"
  5. #include "G4UnitsTable.hh"
  6. #include <mutex>
  7. using namespace B1;
  8. std::mutex EventAction::myLock;
  9. G4int EventAction::TotalCount = 0;
  10. G4int EventAction::TempCount = 0;
  11. EventAction::EventAction(RunAction* runAction) : G4UserEventAction(), fRunAction(runAction) {}
  12. EventAction::~EventAction() {}
  13. void EventAction::BeginOfEventAction(const G4Event*) {
  14.     fEdep = 0.;
  15. }
  16. void EventAction::EndOfEventAction(const G4Event* aEvent) {
  17.     std::lock_guard<std::mutex> lock(myLock); // 加锁
  18.     TotalCount++;
  19.     TempCount++;
  20.     G4cout << "*!!!!!!!!!!!!!!!!!![b][/b]*** EndOfEventAction, TotalCount: " << TotalCount << G4endl;
  21. }
复制代码

这样修改后,TotalCountTempCount将作为类的静态成员变量,被所有的EventAction对象共享。加锁操作也会确保在修改这些变量时的线程安全性。

希望这次回答能够解决您的问题。如果还有其他问题,请随时提问。

如果回答对你有帮助,请给我一个最佳答案!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-8-9 22:26:00 | 显示全部楼层
学习编程中的Ben 发表于 2023-8-9 21:57
根据您提供的代码,我注意到您的累加计数器可能没有正确工作的原因是,每次执行EndOfEventAction函数时,您 ...

大哥,你就是个小天才,我成功了,谢谢
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-5-20 13:49

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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