我在 Visual Studio 2012 中有一个小解决方案。该解决方案由两个项目组成(Scanner 和 TestApp),Scanner 是一个 dll,TestApp 是一个使用 dll 的小应用程序。 我希望 dll 中的函数在线程中运行,并通过队列将其结果报告给 TestApp。 为了测试这一点,我编写了一个最小的应用程序,但根据我启动线程的方式,我得到了不同的结果,我想了解原因。
Scanner.h 文件如下所示:
#pragma once
#include <iostream>
#include <string>
#include <stdint.h>
#include <atomic>
#include <future>
#include <thread>
#include "version.h"
#include "threadsafe_queue.h"
#include "capture_data.h"
#include "process_data.h"
#ifdef SCANNER_EXPORTS
#define SCANNER_API __declspec(dllexport)
#else
#define SCANNER_API __declspec(dllimport)
#endif
class Scanner
{
public:
static SCANNER_API void run();
static SCANNER_API void stop();
};
扫描仪.cpp:
#include "stdafx.h"
#include "Scanner.h"
std::vector<std::future<int>> my_futures;
void Scanner::run()
{
CaptureData capture_data(1234);
auto t = std::async(std::launch::async, &CaptureData::get_data, capture_data);
my_futures.push_back(std::move(t));
}
void Scanner::stop()
{
for(int n=0; n<my_futures.size(); n++) {
auto e = std::move(my_futures.back());
e.get();
my_futures.pop_back();
}
}
CaptureData 类在 capture_data.h 和 capture_data.cpp 中定义。
capture_data.h:
#pragma once
#include <atomic>
#include <thread>
#include "iq_data.h"
#include "threadsafe_queue.h"
class CaptureData
{
public:
CaptureData(double freq_start);
void configure();
void get_data();
private:
double m_test;
};
capture_data.cpp
#include "stdafx.h"
#include "capture_data.h"
#include "Scanner.h"
ThreadsafeQueue<int> g_queue_1;
SCANNER_API ThreadsafeQueue<int> g_queue_2;
CaptureData::CaptureData(double test)
: m_test(test) {}
void CaptureData::get_data()
{
cout << "1: " << m_test << std::endl;
Sleep(5000);
cout << "2: " << m_test << std::endl;
g_queue_2.push(3);
cout << "Capture has now pushed data" << std::endl;
}
最后是TestApp.cpp:
#include "stdafx.h"
#include "tchar.h"
#include <stdint.h>
#include <string>
#include "Scanner.h"
SCANNER_API extern ThreadsafeQueue<int> g_queue_2;
int _tmain(int argc, _TCHAR* argv[])
{
Scanner scanner;
scanner.run();
cout << "TestApp waiting for data..." << std::endl;
int data;
g_queue_2.wait_and_pop(data);
cout << "TestApp got data: " << data << std::endl;
scanner.stop();
return 0;
}
在 Scanner.cpp 中,我尝试以两种不同的方式启动线程,第一种方式:
auto t = std::async(std::launch::async, &CaptureData::get_data, capture_data);
第二种方法是引用对象“capture_data”:
auto t = std::async(std::launch::async, &CaptureData::get_data, &capture_data);
第一种方法似乎可以正常工作,因为我希望应用程序能够工作,并且我在终端中得到以下打印输出:
TestApp waiting for data...
1: 1234
2: 1234
Capture has now pushed data
TestApp got data: 3
Press any key to continue...
如果我使用第二种方式,我得到:
TestApp waiting for data...
1: 6.95166e-310
2: 6.95166e-310
Capture has now pushed data
TestApp got data: 3
Press any key to continue...
所以,我不明白的是为什么变量“m_test”在第二种情况下会变得困惑。 如果有人能阐明这一点,我将非常感激。
/M
最佳答案
在下面的代码中:
void Scanner::run()
{
CaptureData capture_data(1234);
auto t = std::async(std::launch::async, &CaptureData::get_data, capture_data);
my_futures.push_back(std::move(t));
}
capture_data
是一个局部变量,它超出范围并在函数返回时被销毁。如果将指向该变量的指针传递给异步,该指针将成为悬空指针,导致未定义的行为。如果您按值传递它,则不会发生这种情况,就像在上面的代码片段中所做的那样。
关于c++ - 使用 std::async 引用对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47155293/