我目前正在尝试将新的 C++20 协程与 boost::asio 一起使用。然而,我正在努力找出如何实现自定义可等待函数(例如 boost::asio::read_async)。我试图解决的问题如下:
我有一个连接对象,我可以在其中发出多个请求并注册响应的回调。不保证响应会按照请求的顺序到达。我尝试用自定义的可等待包装回调,但是我无法在协程中 co_await ,因为 boost::asio::awaitable 中没有适用于我的可等待类型的await_transform。
我尝试将回调包装成可等待的代码改编自此处: https://books.google.de/books ?id=tJIREAAAQBAJ&pg=PA457
auto async_request(const request& r)
{
struct awaitable
{
client* cli;
request req;
response resp{};
bool await_ready() { return false; }
void await_suspend(std::coroutine_handle<> h)
{
cli->send(req, [this, h](const response& r)
{
resp = r;
h.resume();
});
}
auto await_resume()
{
return resp;
}
};
return awaitable{this, r};
}
Run Code Online (Sandbox Code Playgroud)
我尝试调用一个 boost 协程,如下所示:
boost::asio::awaitable<void> network::sts::client::connect()
{
//...
auto res = co_await async_request(make_sts_connect());
//...
}
Run Code Online (Sandbox Code Playgroud)
给我以下错误:
error C2664: 'boost::asio::detail::awaitable_frame_base<Executor>::await_transform::result boost::asio::detail::awaitable_frame_base<Executor>::await_transform(boost::asio::this_coro::executor_t) …Run Code Online (Sandbox Code Playgroud) 在下面的示例中,我为我的应用程序启动一个工作线程。后来我发布了一些作品。为了防止它过早返回,我必须确保“工作”出色。我使用 work_guard 对象来执行此操作。然而,我发现了另外两种“确保”工作的方法。我应该在整个申请过程中使用哪一个?有什么区别吗?
#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <syncstream>
#include <iostream>
namespace asio = boost::asio;
int main() {
asio::io_context workerIO;
boost::thread workerThread;
{
// ensure the worker io context stands by until work is posted at a later time
// one of the below is needed for the worker to execute work which one should I use?
auto prodWork = asio::make_work_guard(workerIO);
// prodWork.reset(); // can be cleared
asio::any_io_executor prodWork2 = asio::prefer(workerIO.get_executor(), asio::execution::outstanding_work_t::tracked);
// prodWork2 = asio::any_io_executor{}; // can be cleared …Run Code Online (Sandbox Code Playgroud) 我尝试使用无堆栈 C++20协程和asio(不带 boost)创建一个应用程序。因此我使用的是MSVC编译器。可以使用/await标志编译以下代码片段:
#include <asio.hpp>
int main(){
asio::io_context ioContext(1);
asio::co_spawn(ioContext.get_executor(), []() -> asio::awaitable<void> { return {}; }, asio::detached);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
一旦我添加了编译器标志/std:c++latest,代码就不再编译了。我收到一个错误:
...\_libs\asio-1.16.1\include\asio\async_result.hpp(289,1): error C7602: 'asio::async_result': the associated constraints are not satisfied (compiling source file main.cpp)
...\_libs\asio-1.16.1\include\asio\async_result.hpp(107): message : see declaration of 'asio::async_result' (compiling source file main.cpp)
...\_libs\asio-1.16.1\include\asio\impl\co_spawn.hpp(139): message : see reference to class template instantiation 'asio::detail::async_result_has_initiate_memfn<CompletionToken,asio::detail::awaitable_signature<asio::awaitable<void,asio::executor>>>' being compiled
with
[
CompletionToken=const asio::detached_t &
] (compiling source file main.cpp)
...\main.cpp(4): …Run Code Online (Sandbox Code Playgroud) 我需要找到录制音频流的最佳方式.我已经在C++中构建了低级代码,并将其部分接口到C#.
所以我有一个C++回调,给我一个浮点数组 - 音频信号.目前,我的C++ lib正在以wav格式将数据直接记录到文件中,它只是在结束录制时通知我的C#应用程序.
但是,我希望在UI方面有更多的交互性,比如"无限"进度条,记录的数据量,取消按钮等等,并且因为它最坏的时候会是一分钟,也许最好将它保存在内存中.我对.NET和C#内存管理知之甚少,所以我不知道如何有效地实现它.
在C#中是否有任何快速可调整大小的容器,我可以将数据放入其中并稍后像数组一样访问它?
我还想建立一个波形图像.我已经用C++完成了这些事情,但不知怎的,我不喜欢写太多消息,转移对象等的想法.
所以把事情放在一起:
我有C++非托管回调,它做了一些东西,从内部我想在处理数据后调用C#方法,C原型将是:
void process(float**signal,int n); (通常[2] [n] - 用于立体声)
什么是C#等价物,我如何从C++回调中调用它?
写连续流的最佳类是什么(如mem.put(float [] [] data,int size))然后将其作为数组或其他简单方法读取(例如从中保存wav文件或制作波形位图)
如果我在C#中这样做会不会有重大的性能损失?(托管c ++包装器调用c#函数等...可能还有一些DSP的东西)或者我只是偏执狂?:)
干杯,
pablox
好的,我这样解决了:
在我的C++头文件中,我得到了传输结构:
public ref struct CVAudio {
public:
float *left;
float *right;
int length;
};
Run Code Online (Sandbox Code Playgroud)
然后在托管C++类中我声明了:
delegate void GetAudioData([In, Out] CVAudio^ audio);
Run Code Online (Sandbox Code Playgroud)
然后我可以用它作为初始化音频的方法的参数:
void initializeSoundSystem(void *HWnd, GetAudioData ^audio);
Run Code Online (Sandbox Code Playgroud)
那个代表也有一个C原型
typedef void (CALLBACK *GETAUDIODATA)(CVAudio ^a);
Run Code Online (Sandbox Code Playgroud)
在内部C++类中使用的是:
void initializeSoundSystem(HWND HWnd, GETAUDIODATA audio);
Run Code Online (Sandbox Code Playgroud)
然后第一种方法的主体是:
void VDAudio::initializeSoundSystem(void *HWnd, GetAudioData ^audio)
{
HWND h = (HWND) HWnd; …Run Code Online (Sandbox Code Playgroud) 我正在对吉他(小提琴)英雄进行克隆编程,作为本学年的期末项目。
这个想法是从我的电小提琴中获取输入,通过 FFT 对其进行分析,进行一些逻辑和绘图,然后通过扬声器输出。也许并行线程中的一些步骤。
我已经实现了 Asio 低延迟输入输出,但在实现实时 FFT 时遇到了很大的问题。
这是设置 asioOut 和 SampleAggregator 的代码。样本聚合器应存储每次调用 AudioAvailable() 时添加的样本,并在样本数量超过 fftLength 时触发 FFT 计算。
private static int fftLength = 8192;
private SampleAggregator sampleAggregator = new SampleAggregator(fftLength);
void asioStartPlaying(object sender, EventArgs e)
{
sampleAggregator.PerformFFT = true;
sampleAggregator.FftCalculated += new EventHandler<FftEventArgs>(FftCalculated);
var asioOut = new AsioOut();
BufferedWaveProvider wavprov = new BufferedWaveProvider(new WaveFormat(48000, 1));
asioOut.AudioAvailable += new EventHandler<AsioAudioAvailableEventArgs> (asio_DataAvailable);
asioOut.InitRecordAndPlayback(wavprov, 1, 25);
asioOut.Play();
}
void asio_DataAvailable(object sender, AsioAudioAvailableEventArgs e)
{
byte[] buf = new byte[e.SamplesPerBuffer*4];
for (int …Run Code Online (Sandbox Code Playgroud) 我正在尝试在 Win7 上使用 PyAudio 连接到 PreSonus AudioBox 1818VSL,但在一次录制 2 个以上通道(立体声)时遇到一些问题。PreSonus 驱动程序创建许多立体声输入音频设备(例如立体声通道 1&2、3&4 等)和 18 个输入通道 ASIO 设备。我可以毫无问题地从任何立体声设备进行录音。为了最大限度地减少延迟并从 > 2 个通道进行录制,我尝试使用 ASIO 设备。
我一直在使用 PyAudio 的版本我一直在使用来自http://www.lfd.uci.edu/~gohlke/pythonlibs/#pyaudio,它编译了对 ASIO、DS、WMME、WASAPI、WDMKS 的支持。
致电pyaudio_handle.is_format_supported()显示 ASIO 设备支持 44.1、48 和 96 kHz 的 8 至 32 位数据。
下面是返回的字典pa.get_device_info_by_index(32)
{'defaultHighInputLatency': 0.046439909297052155,
'defaultHighOutputLatency': 0.046439909297052155,
'defaultLowInputLatency': 0.046439909297052155,
'defaultLowOutputLatency': 0.046439909297052155,
'defaultSampleRate': 44100.0,
'hostApi': 2L,
'index': 32,
'maxInputChannels': 18L,
'maxOutputChannels': 18L,
'name': u'AudioBox ASIO Driver',
'structVersion': 2L}
Run Code Online (Sandbox Code Playgroud)
下面是我用来创建 PyAudio 输入流的代码。回调函数只是将数据推送到列表中并返回,pyaudio.paContinue直到获得所需的样本量,然后返回pyaudio.paComplete。
pyaudio_handle = pyaudio.PyAudio()
stream …Run Code Online (Sandbox Code Playgroud) 我正在使用 Gervill 的软件合成器加载 SF2 音库,并从 Midi 键盘播放音乐,我想知道是否可以通过 ASIO 播放输出,可能是通过JAsioHost。我一直在尝试查看 Gervill 源代码以查找原始音频数据何时实际传递给音频驱动程序,但我似乎无法找到它,即使那样,我也不确定这是否是正确的做法。
我使用的链是使用 SF2loader 将声音字体加载到默认合成器中,然后我使用通道 noteOn 方法播放音符。
我正在使用最新的 ASIO 版本(截至目前 1.18.0)。目前正在设计一个带有计时器(用于超时)的多线程异步 TCP 服务器。我有一个io_context有多个线程调用其run()函数的单个线程。我接受这样的新连接:
void Server::AcceptConnection()
{
acceptor_.async_accept(asio::make_strand(io_context_),
[this](const asio::error_code& error, asio::ip::tcp::socket peer) {
if (!error) {
std::make_shared<Session>(std::move(peer))->run();
}
AcceptConnection();
});
}
Run Code Online (Sandbox Code Playgroud)
这是该类的精简版本Session:
class Session : public std::enable_shared_from_this<Session>
{
public:
Session(asio::ip::tcp::socket&& peer) : peer_(std::move(peer)) {}
void run()
{
/*
asio::async_read(peer_, some_buffers_, some_callback_);
timeout_timer_.expires_after();
timeout_timer_.async_wait();
// etc
*/
}
private:
asio::ip::tcp::socket peer_;
asio::steady_timer timeout_timer_{peer_.get_executor()};
}
Run Code Online (Sandbox Code Playgroud)
请注意定时器的初始化。另外,请注意,我没有对套接字和计时器的异步处理程序使用任何类型的strand::wrap()或asio::bind_executor()包装器,因为据我了解,如果我使用正确的执行程序初始化对象,则不再需要它们。
这里的问题是:这是在 TCP 连接正在使用的同一链内使用计时器来处理链内 TCP 连接的正确方法吗?
注意:计时器用于在超时后中止 TCP 连接。
我想尝试与 asio 一起使用 c++20 协程。在一个简单的测试中,三个协程将在具有 4 个线程的 asio::thread_pool 上执行。当我运行测试时,所有协程都是一个接一个地执行的,而不是同时执行。这不是我所期望的行为。我认为 asio::thread_pool 的执行器会将协程分布在多个线程上。有什么是我忽略的吗?
using namespace asio::experimental::awaitable_operators;
asio::awaitable<std::string> one() {
std::this_thread::sleep_for( 1s );
co_return "egy";
}
asio::awaitable<std::string> two() {
std::this_thread::sleep_for( 1s );
co_return "ketto";
}
asio::awaitable<std::string> three() {
std::this_thread::sleep_for( 1s );
co_return "harom";
}
asio::awaitable<void> run_all() {
auto [first, second, third] = co_await( one() &&
two() &&
three() );
}
int main() {
asio::thread_pool pool( 4 );
co_spawn( pool, run_all(), asio::detached );
pool.join();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
运行示例: https: //godbolt.org/z/affo4EvWb
例如,在随机访问设备上调用同步读取操作并抛出异常时,我们如何知道读取了多少字节random_access_file?
这是否不受支持,并且要知道读取了多少字节,应该采取过载boost::system::error_code ec?
error_code ec;
size_t s = a.read_some_at(offset, buffers, ec);
offset += s; // need to be done before unwinding
if (ec) throw system_error(ec);
return s;
Run Code Online (Sandbox Code Playgroud)