簡體   English   中英

C ++多線程堆棧溢出

[英]C++ Multithreading stack overflow

我試圖在我的C ++應用程序中隔離多線程問題。

下面的處理程序在輔助線程中創建和“處理”。

struct Handler 
{
    void process(const std::vector<size_t> ops)
    {
        std::vector<size_t>::const_iterator iter = ops.cbegin();
        while( iter != ops.cend() ) {
            processOperation( op );
        }
    }

    void processOperation(std::vector<size_t>::const_iterator& iter)
    {
        size_t op = *iter;
        iter++;

        switch( op ) {
            case frame_push : { 
                processOperation( iter );
                break;
            }
            case frame_pop : { 
                return;
            }
            default : { break; }
        }
    }
};

如上所示,如果當前的“ op”等於frame_push,則processOperation()會遞歸調用自身。

我知道這里足夠的遞歸操作會導致調用堆棧溢出。 但是,當我在輔助線程而不是主線程上運行此Handler時,這似乎發生得更快。

似乎調用棧溢出的可能性不是我這里唯一的問題。 可能還會有折返問題嗎?

我將不勝感激。 謝謝!

您正在嘗試使用while循環和recursion兩種方式遍歷向量。 您必須使用其中之一才能使代碼正常工作。 如果僅嘗試以一種方式實現它,則不應有任何堆棧溢出條件。 以下是修改后的代碼,該代碼清楚地隔離了兩種類型的遞歸。 希望這有助於解決您的問題。

#include <iostream>
#include <vector>

using namespace std;

struct Handler 
{
    void processOperation(size_t& op)
    {
        std::cout << "Processing : " << op << std::endl;
        // TODO: Actual processing
    }

    void process(const std::vector<size_t> ops)
    {
        std::vector<size_t>::const_iterator iter = ops.cbegin();
        while( iter != ops.cend() ) {
            size_t op = *iter;
            processOperation(op);
            iter++;
        }
    }

    void processRecursive(std::vector<size_t>::const_iterator iter,
        std::vector<size_t>::const_iterator end)
    {
        if (iter != end)
        {
            size_t op = *iter;
            processOperation(op);
            processRecursive(++iter, end);
        }
    }
};

int main() {
    // your code goes here
    std::vector<size_t> ops;
    ops.push_back(1);
    ops.push_back(2);
    ops.push_back(3);
    ops.push_back(4);

    Handler h;
    h.process(ops);
    h.processRecursive(ops.cbegin(), ops.cend());
    return 0;
}

您成功消除的第一件事是“ ops”的所有權,因為您按值傳遞了它,因此我們正在處理線程本地副本:

void process(const std::vector<size_t> ops)

然后創建一個迭代器

std::vector<size_t>::const_iterator iter = ops.cbegin();

您可能將其寫為:

auto iter = ops.begin();

但是沒問題。 現在我們設置循環約束:

while( iter != ops.cend() ) {

但是,這在遞歸調用之外。 因此,只有當我們離開遞歸調用時才會檢查它。

void processOperation(std::vector<size_t>::const_iterator& iter)
{
    size_t op = *iter;
    iter++;

    switch( op ) {
        case frame_push : { 
            processOperation( iter );
            break;
        }
        case frame_pop : { 
            return;
        }
        default : { break; }
    }
}

容器末尾的此調用中沒有代碼。 我猜想frame_push和frame_pop允許您為將替換為默認情況的情況創建范圍,因此需要遞歸。

如果是這樣的話,最好實現自己的框架堆棧。

#include <vector>
#include <iostream>
#include <thread>

enum Operands { frame_push, frame_pop, other };

struct Frame {};

struct Handler
{
    size_t maxDepth, pushCount, popCount;

    Handler() : maxDepth(0), pushCount(0), popCount(0) {}

    void handle(const std::vector<Operands> ops_)
    {
        std::vector<Frame> stack;
        stack.reserve(256);
        stack.emplace_back(); // Create a default Frame
        for (auto iter = ops_.cbegin(); iter != ops_.cend(); ++iter) {
            switch (*iter) {
                case frame_push:
                    // make a copy of the current frame,
                    // remove the 'stack.back()' if new frames should
                    // start empty
                    ++pushCount;
                    stack.emplace_back(stack.back());
                    maxDepth = std::max(maxDepth, stack.size());
                break;
                case frame_pop:
                    stack.pop_back();
                    ++popCount;
                break;
                default: {
                    Frame& frame = stack.back();
                    (void)frame;
                }
                break;
            }
        }
        std::this_thread::yield();
        std::cout << "ops len " << ops_.size()
            << ", pushCount " << pushCount
            << ", popCount " << popCount
            << ", maxDepth " << maxDepth
            << std::endl;
        std::this_thread::yield();
    }
};

int main()
{
    std::vector<Operands> ops = {
        frame_push, other, other,
            frame_push, other, frame_pop,
            other,
            frame_push, frame_pop,
            other,
            frame_push,
                frame_push, other, other, frame_pop,
            frame_pop,
        frame_pop
    };

    Handler h;
    std::thread t1(&Handler::handle, &h, ops);
    t1.join();
}

參見http://goo.gl/dZMRDC

正如評論員Jeremy Friesner所建議的那樣,線程的默認堆棧大小太小並導致溢出。 我可以通過使用以下代碼為boost :: thread設置自定義堆棧大小(此功能對於std :: thread顯然不存在)來解決此問題:

boost::thread::attributes attributes;
attributes.set_stack_size( customStackSize );

boost::thread aThread( attributes, /* function binding here */ );

但是,正如Tsyvarev所建議的那樣,真正的解決方案是替換遞歸行為。

謝謝大家!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM