猪猪虾 发表于 2023-8-9 21:57:04

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

.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();
}
}

isdkz 发表于 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>可以确保在函数结束时自动释放锁,避免了手动加锁和解锁可能出现的错误。

陶远航 发表于 2023-8-9 21:57:23

根据你提供的代码,我发现有几个问题可能会导致累加结果不正确:

1. 在 EventAction 类中,TotalCount 和 TempCount 变量没有初始化为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;
}


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

如果问题仍然存在,请提供更多关于你的代码和问题的详细信息,我将尽力帮助你解决。
如果问题已经解决,请设置最佳答案

Mike_python小 发表于 2023-8-9 21:57:23

根据你提供的代码,我发现在EndOfEventAction函数中,每个事件结束后都会增加TotalCount和TempCount的值。你使用了互斥锁来保护这两个变量,确保在多线程环境下的安全访问。但是,问题可能出现在主函数中的调用部分,你可能需要多次运行线程来达到累加的效果。

你可以尝试在主函数中创建多个线程,并在每个线程中执行事件的开始和结束操作。这样才能触发多个事件,达到累加的目的。下面是一种可能的修改示例:


#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 << "*!!!!!!!!!!!!!!!!!!*** EndOfEventAction, TotalCount: " << totalCount << std::endl;

    // 在作用域结束时自动解锁
}

int main() {
    const int numThreads = 20;
    std::thread threads;

    for (int i = 0; i < numThreads; ++i) {
      threads = std::thread(EndOfEventAction);
    }

    for (int i = 0; i < numThreads; ++i) {
      threads.join();
    }

    return 0;
}


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

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

球一个最佳答案谢谢啦!这对我非常重要!{:10_254:}{:10_254:}{:10_254:}

学习编程中的Ben 发表于 2023-8-9 21:57:29

根据您提供的代码,我注意到您的累加计数器可能没有正确工作的原因是,每次执行EndOfEventAction函数时,您都会创建一个新的EventAction对象,而每个对象都有自己的TotalCount和TempCount变量。这导致了每次累加都是从零开始。

为了解决这个问题,您可以将TotalCount和TempCount声明为静态成员变量,这样它们将在所有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 << "*!!!!!!!!!!!!!!!!!!*** EndOfEventAction, TotalCount: " << TotalCount << G4endl;
}


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

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

如果回答对你有帮助,请给我一个最佳答案!{:10_254:}{:10_254:}{:10_254:}

猪猪虾 发表于 2023-8-9 22:26:00

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

大哥,你就是个小天才,我成功了,谢谢
页: [1]
查看完整版本: 线程锁问题,但是为什么累加还是不对,设的是20次运行