[英]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();
}
正如評論員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.