在我的应用程序中,我使用 coroutine2 来生成一些我必须从流中解码的对象。这些对象是使用协程生成的。我的问题是,一旦我到达流的末尾并且理论上会抛出 std::ios_base::failure 我的应用程序在某些条件下崩溃。
提供此功能的函数在 C++ 中实现,导出为 C 函数并从 C# 调用。这一切都发生在 Windows 10 x64 上的 32 位进程上。不幸的是,当我在调试模式下从 C# 开始我的测试而没有附加本机调试器时,它只会可靠地崩溃。一旦我附加了本机调试器,一切都会按预期工作。
这是一个重现此问题的小型测试应用程序:
api.h
#pragma once
extern "C" __declspec(dllexport) int __cdecl test();
api.cpp
#include <iostream>
#include <vector>
#include <sstream>
#include "Api.h"
#define BOOST_COROUTINES2_SOURCE
#include <boost/coroutine2/coroutine.hpp>
int test()
{
using coro_t = boost::coroutines2::coroutine<bool>;
coro_t::pull_type source([](coro_t::push_type& yield) {
std::vector<char> buffer(200300, 0);
std::stringstream stream;
stream.write(buffer.data(), buffer.size());
stream.exceptions(std::ios_base::eofbit | std::ios_base::badbit | std::ios_base::failbit);
try {
std::vector<char> dest(100100, 0);
while (stream.good() && !stream.eof()) {
stream.read(&dest[0], dest.size());
std::cerr << "CORO: read: " << stream.gcount() << std::endl;
}
}
catch (const std::exception& ex) {
std::cerr << "CORO: caught ex: " << ex.what() << std::endl;
}
catch (...) {
std::cerr << "CORO: caught unknown exception." << std::endl;
}
});
std::cout << "SUCCESS" << std::endl;
return 0;
}
C#:
using System;
using System.Runtime.InteropServices;
namespace CoroutinesTest
{
class Program
{
[DllImport("Api.dll", EntryPoint = "test", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
internal static extern Int32 test();
static void Main(string[] args)
{
test();
Console.WriteLine("SUCCESS");
}
}
}
一些细节:
- 我们正在使用 Visual Studio 2015 14 并动态链接 c++ 运行时。
- 测试库静态链接 Boost 1.63.0。
- 我们还尝试通过直接从 c++ 和 python 调用功能来重现此行为。到目前为止,这两项测试都没有成功。
- 如果您使用 CTRL F5 启动 c# 代码(意味着没有 .net 调试器),一切都会好起来的。仅当您使用 F5(即附加的 .NET 调试器)启动它时,Visual Studio 实例才会崩溃。还要确保不要启用本机调试器!
- 注意:如果我们不使用流中的异常,一切都很好。不幸的是,解码我的对象的代码使用了它们,因此我无法避免这种情况。
如果您对这里可能出现的问题或解决方案有一些额外的提示,那就太棒了。我不完全确定这是否是一个 boost 错误,也可能是 c# 调试器干扰了 boost-context。
提前致谢!最好的问候,迈克尔