【问题标题】:boost::mutex::scoped_lock has been used and It sometimes throws the exceptionboost::mutex::scoped_lock 已被使用,有时会抛出异常
【发布时间】:2013-03-13 08:01:53
【问题描述】:

我在我的多线程代码中使用 scoped_lock 来独占访问代码的某些部分,但有时它会抛出异常访问冲突写入位置 ...

boost::mutex mMutex;    
boost::condition mInputQueueNotEmpty;    
Job* MyThreadPool<Job, JobOutput>::GetNextJob()  
{    
    boost::mutex::scoped_lock lock(mMutex);

    while (mInputQueue.empty())
        mInputQueueNotEmpty.wait(lock);

    // Do something ...
}

我跟踪了代码,发现 basic_timed_mutex 类中有一个变量 active_count,并且每当发生运行时错误时,该变量都未初始化。 运行时错误发生在这里:

bool try_lock()
{
    return !win32::interlocked_bit_test_and_set(&active_count,lock_flag_bit);
}

我不知道该怎么办!因为我无权访问这个变量,也不负责初始化它。

更新

我的函数类是这样的:

#pragma once

#include <vector.h>
#include <boost/thread.hpp>
#include "MyThread.h"
#include <queue>
#include <boost/thread/condition.hpp>

template <class Job, class JobOutput>
class MyThreadPool
{
public:
    MyThreadPool(int processJobWhenArrived);        
    virtual ~MyThreadPool(void);
        void    Initialize(int ThreadsCount);
        void    AddJob(Job* job);
        void    StartProcess();
        Job*    GetNextJob();
    virtual void    FinishJob(Job* job, JobOutput* jobOutput);
        void    WaitUntilAllJobsProcessed();

public:
    vector<MyThread<Job, JobOutput>*> mThreads;

    queue<Job*> mInputQueue;
    queue<pair<Job*,JobOutput*>> mOutputQueue;

    boost::mutex        mMutexAdd;
    boost::mutex        mMutex;
    boost::condition    mInputQueueNotEmpty;
    boost::mutex        mJobOutputMutex;
    boost::mutex        mJobsMutex;
    boost::condition    mProcessJobs;
    bool            mStartProcessJobs;
    int         mJobsInputCount;
    int         mJobsOutputCount;
    int         mPrevJobsOutputCount;
    bool            mProcessJobWhenArrived;
};

template <class Job, class JobOutput>
void MyThreadPool<Job, JobOutput>::Initialize(int threadsCount)
{
    mStartProcessJobs = false;
    for (int t = 0; t < threadsCount; t++)
        mThreads.push_back(new MyThread<Job, JobOutput>(this));
}

template <class Job, class JobOutput>
void MyThreadPool<Job, JobOutput>::AddJob(Job* job)
{
    boost::mutex::scoped_lock lock(mMutexAdd);
    mInputQueue.push(job);
    mJobsInputCount++;

    if (mProcessJobWhenArrived)
        mInputQueueNotEmpty.notify_all();
}

template <class Job, class JobOutput>
Job* MyThreadPool<Job, JobOutput>::GetNextJob()
{
    boost::mutex::scoped_lock lock(mMutex);

    if (mInputQueue.empty() && mStartProcessJobs && mJobsInputCount == mJobsOutputCount)
        mProcessJobs.notify_one();

    while (mInputQueue.empty())
        mInputQueueNotEmpty.wait(lock);

    Job* job = mInputQueue.front();
    mInputQueue.pop();

    return job;
}

这是我使用 GetNextJob 函数的代码:

#pragma once

#include <MyMemory.h>
#include <boost/thread.hpp>

template <class Job, class JobOutput>
class MyThreadPool;

template <class Job, class JobOutput>
class MyThread
{           
public:
    static void StaticRun(MyThread* p);
    void Run();

public:
    boost::thread   mThread;            
    MyThreadPool<Job, JobOutput>*   mThreadPool;            
};

#include "MyThreadPool.h"
template <class Job, class JobOutput>
MyThread<Job, JobOutput>::MyThread(MyThreadPool<Job, JobOutput>* threadPool)
{
    mThread = boost::thread(StaticRun, this);
    mThreadPool = threadPool;
}

template <class Job, class JobOutput>
void MyThread<Job, JobOutput>::StaticRun(MyThread* p)
{
    p->Run(); 
}

template <class Job, class JobOutput>
void MyThread<Job, JobOutput>::Run()
{
    JobOutput   *jobOutput;
    while (true)
    {
        Job* job = mThreadPool->GetNextJob();
        jobOutput = Process (job);
        mThreadPool->FinishJob(job, jobOutput);
    }

}

有一个类继承了 MyThreadPool

class SsThreadPool : public MyThreadPool<Job, JobOutput>

这就是使用线程池的地方:

class BPS
{
    //...
    SsThreadPool            mJobsThreadPool;
    //...
}
void    BPS::Initialize()
{
    mJobsThreadPool.Initialize(mConcurrentThreadsCount);
}

void    BPS::f()
{
    //...
    for (int i = 0; i < jobsCount; i++)
    {
        //...
        mJobsThreadPool.AddJob(job);
        //...

    }
    mJobsThreadPool.StartProcess(); 
    mJobsThreadPool.WaitUntilAllJobsProcessed();
    //...
}

【问题讨论】:

  • 这是您遇到访问冲突的实际代码吗?
  • mMutex 是全局变量吗?您是否尝试从其他全局对象的构造函数中访问它?
  • 是的,我在这一行遇到异常:boost::mutex::scoped_lock lock(mMutex);
  • @aleguna mMutex 不是全局变量,它是类的非静态成员,我只是从其类的函数中访问它。
  • 然后发布真实代码。我 99.99% 确定问题出在其中,而不是在 boost 中。

标签: c++ boost locking mutex boost-thread


【解决方案1】:

它会引发访问冲突,因为您尝试锁定已破坏的mutex。由于互斥锁是您的类的成员,这意味着您的代码尝试访问已销毁实例的成员函数(“悬空指针”)。要调试这种情况,请在~MyThreadPool 中放置一个断点,然后查看它何时被调用。

【讨论】:

  • 如你所说,我在~MyThreadPool 中设置了断点,但在调用析构函数之前会引发访问冲突。
  • @Samaneh Saadat 好的,我明白了。另一种选择(更糟)是“覆盖”mMutex 的某些部分的堆损坏。无论如何,有些东西破坏了互斥对象。顺便说一句,您使用的是哪个增强版本?
  • 我使用 boost 1.47.0 来立即处理我在 GetNextJob 方法中定义的错误 mMutex,在此修改后,访问冲突在下一行附近引发,现在 mInputQueue 出现问题。
  • @Samaneh Saadat 在本地定义 mMutex 违背了它的目的(它应该在线程之间共享),但是下一个对象成员现在受到影响的事实证实了我的假设:你肯定有堆损坏这会破坏MyThreadPool 实例成员。尝试查看在此崩溃之前调用的函数。
  • @Samaneh Saadat 崩溃点的调用堆栈对您没有帮助。您应该检查通常之前调用的函数。特别要注意不安全的类型转换、调用运算符delete 而不是delete[]、指针算法、继承非虚析构函数。在 MSVC 中启用所有可能的运行时检查,使用调试堆 (msdn.microsoft.com/en-us/library/974tc9t1(v=vs.100).aspx)。谷歌“c++调试堆损坏”。
【解决方案2】:

也许持有互斥锁的对象被破坏,然后有人试图访问互斥锁。可能在您的代码中?

【讨论】:

  • 我不这么认为。该对象的生命周期与程序的生命周期一样长。
猜你喜欢
  • 2013-08-02
  • 2011-01-17
  • 1970-01-01
  • 2011-02-22
  • 1970-01-01
  • 2014-08-06
  • 1970-01-01
  • 1970-01-01
  • 2015-03-04
相关资源
最近更新 更多