【问题标题】:Access std::deque from 3 threads从 3 个线程访问 std::deque
【发布时间】:2014-03-02 01:14:04
【问题描述】:

我有一个 std::deque 类型的缓冲区。 有一个线程要写入其中,另一个线程要从中读取,最后一个线程处理缓冲区中要转发的项目的某些条件。

我只想从 3 个线程安全地访问这个缓冲区。是的,我是初学者 :-)

我创建了一个互斥体,每次我访问缓冲区时,我都会用

包装这个访问
myMutex. lock() ;
// access here
myMutex. unlock() ;

另外,我使用 std::thread myThread(this, &fn) 创建线程。我经常调用 this_thread::sleep() 来减少 CPU 负载

我的问题是我得到 Exeption 说 abort() 已被调用!当我调用 myThread.join() 时,它会失败 怎么回事!!

编辑:添加代码 这是我的主要发送功能

void UDPStreamSender::SendStream(const char* sendMsg, size_t size)
{

    cout << "---- Send Stream starts... ----" << endl;

    char* longMsg = new char[size];
    memcpy(longMsg, sendMsg, size);

    std::thread segThread(&UDPStreamSender::DoSegmentation, this, longMsg, size);
    _isRunning = true;
    std::thread sendThrad(&UDPStreamSender::SendBuffer, this);
    std::thread ackThrad(&UDPStreamSender::AckRecive, this);
    std::thread timeOutThread(&UDPStreamSender::ManageTimeout, this);


    sendThrad.join();
    ackThrad.join();
    timeOutThread.join();

    cout << "---- Send Stream done! ----" << endl;
}

fn 在工作线程上

void UDPStreamSender::DoSegmentation(const char* longMsg, unsigned int size)
{
    Segment* cSeg = new Segment();
    cSeg->seqNum = lastSeqNum;

    msgLength = size;
    msgSegLen = segLength - SEQ_NUM_LEN;

    segmentsNumber = (unsigned int)ceil((float)msgLength / (msgSegLen));

    for (size_t i = 0; i < segmentsNumber; i++)
    {

        cSeg->seqNum++;
        lastSeqNum = cSeg->seqNum;

        cSeg->data = new char[msgSegLen];

        int sendMsgSegLen = msgSegLen;
        if (i == segmentsNumber - 1)
            sendMsgSegLen = msgLength - i*msgSegLen;

        memcpy(cSeg->data, longMsg + i*msgSegLen, sendMsgSegLen);

        // Add to send buffer
        while (sendBuffer->isFull())
        {
            this_thread::sleep_for(std::chrono::milliseconds(50));
        }
        cSeg->isSent = false;

        bufLock.lock();
        std::unique_lock<std::mutex> lock(bufLock);
        sendBuffer->Add(cSeg);
        bufLock.unlock();
    }
    cv.notify_all();
}

void UDPStreamSender::SendBuffer()
{
    bufLock.lock();
    bool hasElms = sendBuffer->hasElems();
    bufLock.unlock();

    while (_isRunning || hasElms)
    {
        bufLock.lock();
        size_t firstUnsent = sendBuffer->firstUnsent();
        size_t buffCount = sendBuffer->count();
        bufLock.unlock();

        if (firstUnsent == buffCount)
        {
            this_thread::sleep_for(std::chrono::milliseconds(50));
            continue;
        }
        for (size_t i = firstUnsent; i < buffCount; i++)
        {
            bufLock.lock();
            Segment sSeg = sendBuffer->at(i);
            int st = SendSegment(&sSeg);
            if (st >= segLength)
            {
                sSeg.isSent = true;
                DWORD j = GetTickCount();
                sSeg.timeOutTick = j + timeOutTicks;
                sendBuffer->Replace(i, &sSeg);
                sendBuffer->sendSeg();
                cout << "SEG sent: SeqNum=" << sSeg.seqNum << endl;
            }
            bufLock.unlock();
        }
        bufLock.lock();
        hasElms = sendBuffer->hasElems();
        bufLock.unlock();
    }
}

void UDPStreamSender::AckRecive()
{
    char* ackMessage;
    while (!_allRecived)
    {
        ackMessage = ackReciver->Recive();

        string ackMsg(ackMessage);
        if (ackMsg.substr(0, 3).compare("ACK") != 0)
            continue;

        unsigned short ackSeqNum = 0;
        memcpy(&ackSeqNum, ackMessage + 3, 2);

        cout << "ACK recieved: seqNum=" << ackSeqNum << endl;

        bufLock.lock();
        sendBuffer->Ack(ackSeqNum);
        _allRecived = !sendBuffer->hasElems();
        bufLock.unlock();
    }
}

void UDPStreamSender::ManageTimeout()
{
    bufLock.lock();
    bool hasElms = sendBuffer->hasElems();
    bufLock.unlock();

    while (hasElms)
    {
        bufLock.lock();

        DWORD segTick = sendBuffer->first().timeOutTick;
        DWORD cTick = GetTickCount();
        if (sendBuffer->hasElems() && cTick > segTick)
        { // timeout, resend all buffer
            sendBuffer->resendAll();
            cout << "Timeout: seqNum=" << sendBuffer->first().seqNum << endl;
        }
        bufLock.unlock();
        this_thread::sleep_for(std::chrono::milliseconds(50));

        bufLock.lock();
        hasElms = sendBuffer->hasElems();
        bufLock.unlock();
    }
}

我知道那里有很多线程,但这只是一个任务!

【问题讨论】:

  • 代码在哪里?您的锁定/解锁 sn-p 并没有说明可能导致问题的实际原因
  • 你试过用-pthread编译吗?
  • @Smac89 我添加了代码。
  • @KerrekSB 我真的不知道什么是“-pthread”!
  • -pthread 是一个编译器选项。就像在不支持的编译器中添加 -std=gnu++11 用于编译 c++11 代码一样,-pthread 用于编译 posix 线程代码。

标签: c++ multithreading mutex


【解决方案1】:

我已经尝试过! 错误来自我锁定()和解锁()互斥锁的方式。

那是插入bufLock.lock(),使用std::unique_lock&lt;std::mutex&gt; mtx_lock(bufLock);锁定双端队列缓冲区。

还需要两个 variable_condition 来处理 isEmpty 和 isFull 的情况来停止转发,添加到缓冲区中。

如果有人觉得有用的话,最后的代码。

注意:此代码占用大量内存并消耗 CPU,未经修改请勿使用。欢迎帮助我:)

void UDPStreamSender::SendStream(const char* sendMsg, size_t size)
{
    InitializeNewSendSession();
    cout << "---- Send Stream starts... ----" << endl;

    char* longMsg = new char[size];
    memcpy(longMsg, sendMsg, size);

    std::thread segThread(&UDPStreamSender::DoSegmentation, this, longMsg, size);
    _isRunning = true;
    std::thread sendThrad(&UDPStreamSender::SendBuffer, this);
    std::thread ackThrad(&UDPStreamSender::AckRecive, this);
    std::thread timeOutThread(&UDPStreamSender::ManageTimeout, this);

    segThread.join();
    sendThrad.join();
    _isRunning = false;
    ackThrad.join();
    timeOutThread.join();

    cout << "---- Send Stream done! ----" << endl;
}

void UDPStreamSender::DoSegmentation(const char* longMsg, unsigned int size)
{
    Segment* cSeg = new Segment();
    cSeg->seqNum = lastSeqNum;

    msgLength = size;
    msgSegLen = segLength - SEQ_NUM_LEN;

    segmentsNumber = (unsigned int)ceil((float)msgLength / (msgSegLen));

    for (size_t i = 0; i < segmentsNumber; i++)
    {

        cSeg->seqNum++;
        lastSeqNum = cSeg->seqNum;

        cSeg->data = new char[msgSegLen];

        int sendMsgSegLen = msgSegLen;
        if (i == segmentsNumber - 1)
            sendMsgSegLen = msgLength - i*msgSegLen;

        memcpy(cSeg->data, longMsg + i*msgSegLen, sendMsgSegLen);

        // Add to send buffer
        std::unique_lock<std::mutex> mtx_lock(bufLock);
        while (sendBuffer->isFull())
        {
            stopifFull.wait(mtx_lock);
        }
        cSeg->isSent = false;

        sendBuffer->Add(cSeg);
        mtx_lock.unlock();
        stopIfEmpty.notify_all();
    }

}

int UDPStreamSender::SendSegment(const Segment* seg)
{
    char* sMsg = new char[segLength];
    sMsg[0] = NULL;

    memcpy(sMsg, (char*)&seg->seqNum, SEQ_NUM_LEN);
    memcpy(sMsg + SEQ_NUM_LEN, seg->data, msgSegLen);

    int st = streamSender->Send(sMsg, segLength);

    delete sMsg;
    return st;
}

void UDPStreamSender::SendBuffer()
{

    bufLock.lock();
    bool hasElms = sendBuffer->hasElems();
    bufLock.unlock();

    while (_isRunning || hasElms)
    {
        std::unique_lock<std::mutex> mtx_lock(bufLock);
        size_t firstUnsent = sendBuffer->firstUnsent();
        size_t buffCount = sendBuffer->count();

        while (!sendBuffer->hasElems())
        {
            stopIfEmpty.wait_for(mtx_lock, std::chrono::milliseconds(100));
            if (_allRecived)
                return;
        }

        for (size_t i = firstUnsent; i < buffCount; i++)
        {

            Segment sSeg = sendBuffer->at(i);
            int st = SendSegment(&sSeg);
            if (st >= segLength)
            {
                sSeg.isSent = true;
                DWORD j = GetTickCount();
                sSeg.timeOutTick = j + timeOutTicks;
                sendBuffer->Replace(i, &sSeg);
                sendBuffer->sendSeg();
                cout << "SEG sent: SeqNum=" << sSeg.seqNum << endl;
            }

        }

        hasElms = sendBuffer->hasElems();

        mtx_lock.unlock();
    }
}

void UDPStreamSender::AckRecive()
{
    char* ackMessage;
    while (!_allRecived)
    {

        ackMessage = ackReciver->Recive();

        string ackMsg(ackMessage);
        if (ackMsg.substr(0, 3).compare("ACK") != 0)
            continue;

        unsigned short ackSeqNum = 0;
        memcpy(&ackSeqNum, ackMessage + 3, 2);

        cout << "ACK recieved: seqNum=" << ackSeqNum << endl;

        std::unique_lock<mutex> mtx_lock(bufLock);
        sendBuffer->Ack(ackSeqNum);
        _allRecived = !sendBuffer->hasElems() || !_isRunning;
        mtx_lock.unlock();
        stopifFull.notify_one();

    }
}

void UDPStreamSender::ManageTimeout()
{
    bufLock.lock();
    bool hasElms = sendBuffer->hasElems();
    bufLock.unlock();

    while (!_allRecived)
    {

        std::unique_lock<mutex> mtx_lock(bufLock);
        while (!sendBuffer->hasElems())
        {
            stopIfEmpty.wait_for(mtx_lock, std::chrono::milliseconds(100));
            if (_allRecived)
                return;
        }

        DWORD segTick = sendBuffer->first().timeOutTick;
        DWORD cTick = GetTickCount();
        if (sendBuffer->hasElems() && cTick > segTick)
        { // timeout, resend all buffer
            sendBuffer->resendAll();
            cout << "Timeout: seqNum=" << sendBuffer->first().seqNum << endl;
        }

        hasElms = sendBuffer->hasElems();

        mtx_lock.unlock();
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-05-23
    • 1970-01-01
    • 2011-05-05
    • 1970-01-01
    • 2017-04-21
    • 1970-01-01
    • 2018-07-14
    相关资源
    最近更新 更多