我的 C++ 类中有几个成员函数,我将它们打包为 dll 并尝试在 C# 应用程序中使用它们。我试图通过简单地使用线程执行它们然后将它们分离()来创建两个异步函数,这样它们就不会阻塞调用者线程直到它们结束。
在基于 C++ 的应用程序中,每当我使用线程以这种方式调用函数时,它们都可以工作,但是当我尝试从 C# 调用我的一个异步函数时,它们似乎执行但没有结果。
这两个异步函数应该在完成工作后创建文本文件,但是它们的普通对应部分却没有!
我将发布我的类定义的片段以及我的 C 包装器(用于 dll )和我的 c# 应用程序部分。
//xGramManipulator.h file
#pragma once
#include <regex>
#include <string>
#include <map>
#include <thread>
#include <mutex>
#include <vector>
class xGramManipulator
{
public:
xGramManipulator();
xGramManipulator(wchar_t* fileToRead);
xGramManipulator(std::wregex monoReg, std::wregex biReg, wchar_t* fileToRead = L"ftext.txt");
~xGramManipulator();
double CreateMonoGram();
double ReadMonoGram();
void SaveMonoGram();
double CreateBiGram();
double ReadBiGram();
void SaveBiGram();
double CreateLists();
void CreateMonoGramAsync();
void CreateBiGramAsync();
priavte:
template<class TypeOne, class TypeTwo>
void WriteToFile(const wchar_t* filePath, std::map<TypeOne, TypeTwo>& container);
private:
std::map<std::wstring, int> monogramStatMap;
std::map<std::wstring, int> bigramStatMap;
std::map<std::wstring, std::wstring> bigramListMap;
std::vector<std::wstring> nextWordResults;
std::unordered_multimap< std::wstring, std::wstring > container;
std::mutex mutex_;
wchar_t* fileToReadFrom;
wchar_t **CStringArraybuffer;
std::wregex monoRegx;
std::wregex biRegx;
std::thread tr1;
std::thread tr2;
std::chrono::high_resolution_clock::time_point startTime;
std::chrono::high_resolution_clock::time_point endTime;
std::chrono::high_resolution_clock::time_point elapsedTime;
};
template <class TypeOne, class TypeTwo>
void xGramManipulator::WriteToFile(const wchar_t* filePath, std::map<TypeOne, TypeTwo>& container)
{
//Because of possible use of threads and inorder to avoid any thread interferance
//i decided to declare it local instead of global.
FILE* filePointer;
//for converting To UTF8 so that our contents are in farsi and not some numeric nonsense!
_wfopen_s(&filePointer, filePath, L"w");
_setmode(_fileno(filePointer), _O_U8TEXT);
wofstream output(filePointer);
for (auto item : container)
{
//write output to file
output << item.first << " : " << item.second << endl;
}
fclose(filePointer);
}
//xGramManipulator.cpp 文件
#include <regex>
#include <fstream>
#include <iostream>
#include <string>
#include <map>
#include <fcntl.h> //for _wfopen_s
#include <io.h> //for _setmode
#include <memory> //for shared_ptr
#include <chrono> //for time benchmarks
#include <thread>
#include <mutex>
#include <unordered_map>
#include <algorithm>
#include <vector>
#include "xGramManipulator.h"
using namespace std;
using namespace chrono;
typedef high_resolution_clock Time;
xGramManipulator::xGramManipulator() : monoRegx(L"\\w+"), biRegx(L"\\w+ \\w+"), fileToReadFrom(L"ftext.txt")
{}
xGramManipulator::xGramManipulator(wchar_t* fileToRead) : monoRegx(L"\\w+"), biRegx(L"\\w+ \\w+"), fileToReadFrom(fileToRead)
{
if (!FileExits(fileToReadFrom))
{
cout << "File doesnt Exists" << endl;
}
}
xGramManipulator::xGramManipulator(wregex monoReg, wregex biReg, wchar_t* fileToRead) : monoRegx(monoReg), biRegx(biReg), fileToReadFrom(fileToRead)
{
if (!FileExits(fileToReadFrom))
{
cout << "File doesnt Exists";
}
}
xGramManipulator::~xGramManipulator()
{
}
//Reads from a file specified in the constructor or through SetFilePathToReadFrom() function
//And then creates a list of monograms.When function execution ends, the elapsed time is returned.
double xGramManipulator::CreateMonoGram()
{
Time::time_point start = Time::now();
ReadMonoGram();
SaveMonoGram();
Time::time_point end = Time::now();
return ElapsedTime(start, end);
}
//Reads from a file specified in the constructor or through SetFilePathToReadFrom() function
//And then creates a list of bigrams.When function execution ends, the elapsed time is returned.
double xGramManipulator::CreateBiGram()
{
Time::time_point start = Time::now();
ReadBiGram();
SaveBiGram();
Time::time_point end = Time::now();
return ElapsedTime(start, end);
}
double xGramManipulator::ReadMonoGram()
{
FILE* filePointer;
wstring inputString = L"";
Time::time_point start = Time::now();
try
{
//converting UTF16 to UTF8 so that we dont get rubbish result!
_wfopen_s(&filePointer, fileToReadFrom, L"r");
_setmode(_fileno(filePointer), _O_U8TEXT);
wifstream file(filePointer);
monogramStatMap.clear();
while (file.good())
{
getline(file, inputString);
for (wsregex_iterator it(inputString.begin(), inputString.end(), monoRegx), it_end; it != it_end; ++it)
{
//Filling the bigram container
//unorderedmap estrefade beshe baraye soorate bishtar
monogramStatMap[(wstring) (*it)[0]]++;
}
}
fclose(filePointer);
}
catch (exception ex)
{
cout << ex.what() << endl;
}
Time::time_point end = Time::now();
return ElapsedTime(start, end);
}
void xGramManipulator::SaveMonoGram()
{
WriteToFile(L"monogramLists.txt", monogramStatMap);
}
double xGramManipulator::ReadBiGram()
{
FILE* filePointer;
wstring inputString = L"";
wstring wstr = L"";
Time::time_point start = Time::now();
try
{
//converting UTF16 to UTF8 so that we dont get rubbish result!
_wfopen_s(&filePointer, fileToReadFrom, L"r");
_setmode(_fileno(filePointer), _O_U8TEXT);
wifstream file(filePointer);
bigramStatMap.clear();
container.clear();
while (file.good())
{
getline(file, inputString);
for (wsregex_iterator it(inputString.begin(), inputString.end(), biRegx), it_end; it != it_end; ++it)
{
//Filling the bigram container
wstr = (wstring) (*it)[0];
bigramStatMap[wstr]++;
//spliting the two words into two items.
bigramListMap[wstr.substr(0, wstr.find(L' '))] = wstr.substr(wstr.find(L' '), wstr.size());
container.emplace(wstr.substr(0, wstr.find(L' ')), wstr.substr(wstr.find(L' '), wstr.size()));
}
}
fclose(filePointer);
}
catch (exception ex)
{
cout << ex.what() << endl;
}
Time::time_point end = Time::now();
return ElapsedTime(start, end);
}
void xGramManipulator::SaveBiGram()
{
WriteToFile(L"bigramStatList.txt", bigramStatMap);
WriteToFile(L"bigramList.txt", bigramListMap);
}
double xGramManipulator::CreateLists()
{
startTime = Time::now();
tr1 = thread(&xGramManipulator::CreateMonoGram, this);
tr2 = thread(&xGramManipulator::CreateBiGram, this);
tr1.join();
tr2.join();
endTime = Time::now();
return ElapsedTime(startTime, endTime);
}
void xGramManipulator::CreateMonoGramAsync()
{
thread t(&xGramManipulator::ReadMonoGram, this);
t.detach();
}
void xGramManipulator::CreateBiGramAsync()
{
//static_cast<void (xGramManipulator::*)()>(&xGramManipulator::ReadMonoGram)
thread t = thread(&xGramManipulator::ReadBiGram, this);
t.detach();
}
这是我的 Dll 定义://CDll.h
#ifdef CDLL_EXPORTS
#define CDLL_API __declspec(dllexport)
#else
#define CDLL_API __declspec(dllimport)
#endif
extern "C"
{
CDLL_API double CreateMonoAndBioGramLists(void); //reads and creates two files for each
CDLL_API double CreateMonoGram(void); //reads and creates a file
CDLL_API double CreateBiGram(void); //reads and creates a file
CDLL_API wchar_t** GetResults(wchar_t* word , int threshold, int* lemgth); //returns the result of the search
CDLL_API double ReadMonoGram(void);
CDLL_API double ReadBiGram(void);
CDLL_API void CreateMonoGramAsync(void);
CDLL_API void CreateBiGramAsync(void);
CDLL_API void* CreateHandle();
CDLL_API void* GetCurrentHandle();
CDLL_API void DisposeCurrentHandle();
CDLL_API void SetCurrentHandle(void* handle);
CDLL_API void* GetHandle();
CDLL_API void DisposeHandle(void*);
}
//CDLL.cpp
#include "CDll.h"
#include "xGramManipulator.h"
#define DLL_EXPORT
extern "C"
{
xGramManipulator *xG;
CDLL_API double CreateMonoAndBioGramLists(void)
{
//return xG.CreateLists();
xG = reinterpret_cast<xGramManipulator*>(GetHandle());
return xG->CreateLists();
}
CDLL_API double CreateMonoGram(void)
{
//return xG.CreateMonoGram();
xG = reinterpret_cast<xGramManipulator*>(GetHandle());
return xG->CreateMonoGram();
}
CDLL_API double CreateBiGram(void)
{
//return xG.CreateBiGram();
xG = reinterpret_cast<xGramManipulator*>(GetHandle());
return xG->CreateBiGram();
}
CDLL_API wchar_t** GetResults(wchar_t* word, int threshold, int* length)
{
//return xG.CGetNextWordsList(word, length, threshold);
xG = reinterpret_cast<xGramManipulator*>(GetHandle());
return xG->CGetNextWordsList(word, length, threshold);
}
CDLL_API double ReadMonoGram(void)
{
//return xG.ReadMonoGram();
xG = reinterpret_cast<xGramManipulator*>(GetHandle());
return xG->ReadMonoGram();
}
CDLL_API double ReadBiGram(void)
{
//return xG.ReadBiGram();
xG = reinterpret_cast<xGramManipulator*>(GetHandle());
return xG->ReadBiGram();
}
CDLL_API void CreateMonoGramAsync(void)
{
//xG.CreateMonoGramAsync();
xG = reinterpret_cast<xGramManipulator*>(GetHandle());
return xG->CreateMonoGramAsync();
}
CDLL_API void CreateBiGramAsync(void)
{
//xG.CreateBiGramAsync();
xG = reinterpret_cast<xGramManipulator*>(GetHandle());
return xG->CreateBiGramAsync();
}
//Handle operations
CDLL_API void* CreateHandle()
{
if (xG == nullptr)
{
xG = new xGramManipulator;
}
else
{
delete xG;
xG = new xGramManipulator;
}
return reinterpret_cast<void*>(xG);
}
CDLL_API void* GetCurrentHandle()
{
return reinterpret_cast<void*>(xG);
}
CDLL_API void DisposeCurrentHandle()
{
delete xG;
xG = nullptr;
}
CDLL_API void SetCurrentHandle(void* handle)
{
if (handle != nullptr)
{
xG = reinterpret_cast<xGramManipulator*>(handle);
}
else
{
xG = new xGramManipulator;
}
}
//factory utility function
//ask question on how to do it.
CDLL_API void* GetHandle()
{
HANDLE handle = GetCurrentHandle();
if (handle != nullptr)
{
return handle;
}
else
{
xG = new xGramManipulator;
handle = reinterpret_cast <void*>(xG);
}
return handle;
}
CDLL_API void DisposeHandle(void* handle)
{
xGramManipulator * tmp = reinterpret_cast<xGramManipulator*>(handle);
delete tmp;
}
注意:
起初不是
xGramManipulator *xG;
我有
xGramManipulator xG;
我只是使用该全局对象来调用成员函数。经过一番思考后,我认为这可能不好,我应该以某种方式使其动态化!?所以我将其更改为当前状态。
请指导我以前的解决方案(使用全局对象 xG)是对还是错,如果错了我会面临什么样的问题?
如果当前的方法是错误的,那我该怎么办?