鱼C论坛

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

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

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

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

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

x
.h函数
//

#ifndef B1EventAction_h
#define B1EventAction_h 1

#include "G4UserEventAction.hh"
#include "globals.hh"
#include <mutex>
/// Event action class
///

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;


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

    G4int TotalCount  = 0;
    G4int TempCount  = 0;
};

}
//
include "G4RunManager.hh"

#include <mutex>
using namespace std;
namespace B1
{

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


EventAction::~EventAction()
{}


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

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

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

.B1EventAction.h
#ifndef B1EventAction_h#define B1EventAction_h 1#include "G4UserEventAction.hh"#include "globals.hh"#include <mutex>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;private:    static std::mutex myLock; // 用于保护需要同步的资源    static G4int TotalCount;    static G4int TempCount;};}#endif
.B1EventAction.cc
#include "B1EventAction.hh"#include "B1RunAction.hh"#include "G4Event.hh"#include "G4RunManager.hh"#include "G4UnitsTable.hh"#include <mutex>using namespace B1;std::mutex EventAction::myLock;G4int EventAction::TotalCount = 0;G4int EventAction::TempCount = 0;EventAction::EventAction(RunAction* runAction) : G4UserEventAction(), 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++;    TempCount++;    G4cout << "*!!!!!!!!!!!!!!!!!![b][/b]*** EndOfEventAction, TotalCount: " << TotalCount << G4endl;}
这样修改后,TotalCountTempCount将作为类的静态成员变量,被所有的EventAction对象共享。加锁操作也会确保在修改这些变量时的线程安全性。

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

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

使用道具 举报

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

修改后的代码如下:
void EventAction::BeginOfEventAction(const G4Event*)
{
    fEdep = 0.;
    myLock.unlock(); // 解锁
}

void EventAction::EndOfEventAction(const G4Event* aEvent)
{
    std::lock_guard<std::mutex> lock(myLock);  // 加锁
    TotalCount ++;
    TempCount ++;
    G4cout<< "*!!!!!!!!!!!!!!!!!!******* EndOfEventAction ,TotalCount : "<< TotalCount <<G4endl;
}

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

使用道具 举报

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

1. 在 EventAction 类中,TotalCountTempCount 变量没有初始化为0。请确保在构造函数中将它们初始化为0。
G4int TotalCount = 0;
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) 即可。
void EventAction::EndOfEventAction(const G4Event* aEvent){
    std::lock_guard<std::mutex> lock(myLock);  // 加锁

    TotalCount++;
    TempCount++;

    G4cout << "*!!!!!!!!!!!!!!!!!!******* EndOfEventAction, TotalCount: " << TotalCount << G4endl;
}

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

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

使用道具 举报

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

你可以尝试在主函数中创建多个线程,并在每个线程中执行事件的开始和结束操作。这样才能触发多个事件,达到累加的目的。下面是一种可能的修改示例:
#include <iostream>#include <thread>#include <mutex>std::mutex mtx;  // 用于保护需要同步的资源int totalCount = 0;int tempCount = 0;void EndOfEventAction() {    std::lock_guard<std::mutex> lock(mtx);  // 加锁    totalCount++;    tempCount++;    std::cout << "*!!!!!!!!!!!!!!!!!![b][/b]*** EndOfEventAction, TotalCount: " << totalCount << std::endl;    // 在作用域结束时自动解锁}int main() {    const int numThreads = 20;    std::thread threads[numThreads];    for (int i = 0; i < numThreads; ++i) {        threads[i] = std::thread(EndOfEventAction);    }    for (int i = 0; i < numThreads; ++i) {        threads[i].join();    }    return 0;}
在上述代码中,我们通过创建多个线程来模拟多个事件的结束操作。每个线程执行EndOfEventAction函数,并在其中加锁、累加计数并输出结果。在主函数中,我们创建了20个线程并等待它们完成。

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

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

使用道具 举报

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

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

.B1EventAction.h
#ifndef B1EventAction_h#define B1EventAction_h 1#include "G4UserEventAction.hh"#include "globals.hh"#include <mutex>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;private:    static std::mutex myLock; // 用于保护需要同步的资源    static G4int TotalCount;    static G4int TempCount;};}#endif
.B1EventAction.cc
#include "B1EventAction.hh"#include "B1RunAction.hh"#include "G4Event.hh"#include "G4RunManager.hh"#include "G4UnitsTable.hh"#include <mutex>using namespace B1;std::mutex EventAction::myLock;G4int EventAction::TotalCount = 0;G4int EventAction::TempCount = 0;EventAction::EventAction(RunAction* runAction) : G4UserEventAction(), 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++;    TempCount++;    G4cout << "*!!!!!!!!!!!!!!!!!![b][/b]*** EndOfEventAction, TotalCount: " << TotalCount << G4endl;}
这样修改后,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-11-16 09:19

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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