【问题标题】:Exception with semaphore wxwidgets信号量 wxwidgets 的异常
【发布时间】:2015-04-07 16:51:51
【问题描述】:

我正在使用来自 WxWidget wiki 的示例来了解如何进行线程间和进程间通信。我不知道为什么该示例有效,但我的代码非常相似,不在“m_QueueCount.Wait(); // 等待信号量(=队列计数变为正数)”行处

当我运行代码时,会显示一个异常:

TeamTranslate.exe 中 0x00B2DB61 处的第一次机会异常:0xC0000005: 访问冲突读取位置 0x00000078。

如果有这个异常的处理程序,程序可能是安全的 继续。

断点在 xstring 文件的第 1749 行。这是代码:

size_type length() const _NOEXCEPT
        {   // return length of sequence
        return (this->_Mysize);
        }

我希望有人能告诉我为什么这不起作用!

提前谢谢你。

标题:

class QueueMSG
{
public:
    QueueMSG(wxEvtHandler* pParent) : m_pParent(pParent) {}
    void AddJob(MessagePTR job); // push a job with given priority class onto the FIFO
    MessagePTR Pop();
    void Report(const Message::tCOMMANDS& cmd, MessagePTR arg); // report back to parent
    size_t Stacksize(); // helper function to return no of pending jobs

private:
    wxEvtHandler* m_pParent;
    std::vector<MessagePTR> m_Jobs; // multimap to reflect prioritization: values with lower keys come first, newer values with same key are appended
    wxMutex m_MutexQueue; // protects queue access
    wxSemaphore m_QueueCount; // semaphore count reflects number of queued jobs
};

class WorkerThread : public wxThread
{
public:
    WorkerThread(QueueMSG* pQueue) : m_pQueue(pQueue) { wxThread::Create(); }

private:
    QueueMSG* m_pQueue;
    BingTranslate bng;
    virtual wxThread::ExitCode Entry();
    virtual void OnJob();
}; // class WorkerThread : public wxThread

cpp:

void QueueMSG::AddJob(MessagePTR job) // push a job with given priority class onto the FIFO
{
    wxMutexLocker lock(m_MutexQueue); // lock the queue
    m_Jobs.push_back(job); // insert the prioritized entry into the multimap
    m_QueueCount.Post(); // new job has arrived: increment semaphore counter
} // void AddJob(const tJOB& job, const tPRIORITY& priority=eNORMAL)

MessagePTR QueueMSG::Pop()
{
    std::vector<MessagePTR>::iterator element;
    m_QueueCount.Wait(); // wait for semaphore (=queue count to become positive)
    m_MutexQueue.Lock(); // lock queue
    element = m_Jobs.begin(); // get the first entry from queue (higher priority classes come first)
    m_Jobs.erase(m_Jobs.begin()); // erase it
    m_MutexQueue.Unlock();// unlock queue
    return *element; // return job entry
} // tJOB Pop()

void QueueMSG::Report(const Message::tCOMMANDS& cmd, MessagePTR arg) // report back to parent
{
    wxThreadEvent evt(wxEVT_THREAD, wxID_ANY);// cmd); // create command event object
    evt.SetPayload<MessagePTR>(arg); // associate string with it
    wxQueueEvent(m_pParent, evt.Clone());
    //m_pParent->AddPendingEvent(evt); // and add it to parent's event queue
} // void Report(const tJOB::tCOMMANDS& cmd, const wxString& arg=wxEmptyString)

size_t QueueMSG::Stacksize()
{
    wxMutexLocker lock(m_MutexQueue); // lock queue until the size has been read
    return m_Jobs.size();
}

void WorkerThread::OnJob()
{
    MessagePTR job = m_pQueue->Pop(); // pop a job from the queue. this will block the worker thread if queue is empty
    bng.translateThis(job);
    switch (job->m_cmd)
    {
    case Message::eID_THREAD_EXIT: // thread should exit
        //Sleep(1000); // wait a while
        throw Message::eID_THREAD_EXIT; // confirm exit command
    case Message::eID_THREAD_JOB: // process a standard job
        //Sleep(2000);
        m_pQueue->Report(Message::eID_THREAD_JOB, job); // report successful completion
        break;
    case Message::eID_THREAD_JOBERR: // process a job that terminates with an error
        m_pQueue->Report(Message::eID_THREAD_JOB, job);
        //Sleep(1000);
        throw Message::eID_THREAD_EXIT; // report exit of worker thread
        break;
    case Message::eID_THREAD_NULL: // dummy command
    default: break; // default
    } // switch(job.m_cmd)
} // virtual void OnJob()    

wxThread::ExitCode WorkerThread::Entry()
{
    Message::tCOMMANDS iErr;
    m_pQueue->Report(Message::eID_THREAD_STARTED, NULL); // tell main thread that worker thread has successfully started
    try {
        while (true)
            OnJob();
    } // this is the main loop: process jobs until a job handler throws
    catch (Message::tCOMMANDS& i) {
        m_pQueue->Report(iErr = i, NULL);
    } // catch return value from error condition
    return (wxThread::ExitCode)iErr; // and return exit code
} // virtual wxThread::ExitCode Entry()

消息类:

#pragma once


#include <cstring>
#include <stdio.h>
#include <wx/string.h>
#include <vector>

#include <memory>

enum MSGDirection{
    in,
    out
};

class Message {

public:
    enum tCOMMANDS // list of commands that are currently implemented
    {
        eID_THREAD_EXIT = wxID_EXIT, // thread should exit or wants to exit
        eID_THREAD_NULL = wxID_HIGHEST + 1, // dummy command
        eID_THREAD_STARTED, // worker thread has started OK
        eID_THREAD_JOB, // process normal job
        eID_THREAD_JOBERR // process errorneous job after which thread likes to exit
    }; // enum tCOMMANDS
    Message(MSGDirection dir, wxString from, wxString message, wxString language_org, wxString language_dest) : m_message(message), m_dir(dir), m_from(from), m_language_orig(language_org), m_language_dest(language_dest), m_cmd(eID_THREAD_EXIT){

        time_t          rawtime;
        struct tm*      timeinfo;
        char            timestamp[100];

        time(&rawtime);
        timeinfo = localtime(&rawtime);
        strftime(timestamp, 100, "%c", timeinfo);
        m_timestamp = timestamp;
    }
    Message() : m_cmd(eID_THREAD_NULL) {}

    ~Message(){ }

    void setIO(MSGDirection dir);
    MSGDirection getIO(){ return m_dir; };
    void setFrom(char* dir);
    wxString getFrom(){ return m_from; };

    void setMSG(wxString dir){
        m_message = dir;
    };
    wxString getMSG(){ return m_message; }
    wxString getTranslated(){ return m_translated; }
    wxString getTimeStamp(){ return m_timestamp; }
    wxString getLanguageOrig(){ return m_language_orig; }

    wxString getLanguageDest(){ return m_language_dest; }
    void  setSrtTranslate(wxString str){ m_translated = str; }
    tCOMMANDS m_cmd;
private:
    MSGDirection m_dir;
    wxString m_language_orig;
    wxString m_from;
    wxString m_message;
    wxString m_timestamp;
    wxString m_language_dest;
    wxString m_translated;

};


typedef std::shared_ptr<Message> MessagePTR;
typedef std::shared_ptr<std::vector<MessagePTR>> MessageQueuePTR;

【问题讨论】:

    标签: c++ visual-studio-2013 wxwidgets


    【解决方案1】:

    在您的QueueMSG::Pop() 调用中,即使迭代器已失效,您也可以使用它。即使您对erase 的调用没有使它失效(它将是,请参阅here),您也不能保证在您解锁互斥锁后它的有效性,因为您可以在该点进行时间切片,然后再进行另一个线程可以修改容器。因此,您应该这样做:

    MessagePtr msg;
    m_QueueCount.Wait();
    {
        wxMutexLocker lock( m_MutexQueue );
        auto element = m_Jobs.begin();
        msg = *element;
        m_Jobs.erase(element);
    }
    return msg;
    

    在他们的代码中 - 与您的代码略有不同 - 他们取消引用迭代器以获取一对并通过此行返回包含的第二个元素:

    element=(m_Jobs.begin())->second; // that '->'
    

    这就是为什么他们不会遭受未定义行为的影响。

    【讨论】:

    • 你应该更喜欢像wxMutexLocker这样的RAII对象,当它被销毁并且element被取消引用之后,它将解锁互斥锁。
    • @Rollen 我用过你的代码,我得到了同样的异常:/
    • MessagePtr..的数据类型是什么,是如何创建的?
    • @Daniel976034,你也看过堆栈帧,看看抛出异常时做了哪些调用?
    • @RollenD'Souza TeamTranslate.exe!std::basic_string&lt;wchar_t,std::char_traits&lt;wchar_t&gt;,std::allocator&lt;wchar_t&gt; &gt;::size() Line 1749 C++ 我要添加消息类的代码_ DONE。我认为问题出在信号量上。当我调试两个项目时, m_queueCount 在每个项目中采用不同的值。我的意思是,在示例中我可以看到“m_semaphore 0x00000180 void *”,但在我的项目中,没有“m_semaphore”。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-27
    • 2022-01-11
    • 1970-01-01
    • 1970-01-01
    • 2017-06-03
    • 1970-01-01
    相关资源
    最近更新 更多