使用/ clr标志编译托管C ++代码时,编译器不允许使用include。我试图将我的非托管C ++代码移植到托管C ++环境中。我看到C#有替代Task和TaskCompletionSource替换期货和承诺,但我没有看到托管C ++中有这些选项。我需要与一些C ++非托管库执行互操作,因此我无法完全切换到C#。我之间仍然需要一个C ++层。如何在托管C ++中实现未来/承诺功能?
以下是C ++中非托管代码的示例,它在没有/ clr标志的情况下进行编译:
int Foo(std::future<int> &fur) {
int result = 1;
int value = fut.get();
// Do something with value
return result;
}
int main() {
int x;
std::promise<int> p;
std::future<int> f = p.get_future();
std::future<int> fut = std::async(Foo, std::ref(f));
int val = 1;
p.set_value(val);
x = fut.get();
}
我希望能够在C ++ / CLI中执行此操作
答案 0 :(得分:2)
更新(一些早期评论在此重新制定):
即使我们选择公共语言运行时支持(C ++ - Cli,CLR),许多标准C ++库也可以免费使用。但其中一些是不可用的,例如被质疑的那些。
如果我们添加这样的标题,我们会收到以下错误:
&#39;使用/ clr或/ clr:pure进行编译时,不支持<future>
。 &#39;
这对我们来说意味着这样的代码可以保留在一个单独的dll中,或者我们必须重构我们的代码或者我们需要一个C#实现所提到的库,如this一个。
<强>答案强>:
问题本身包含正确的答案,因此可以使用以下方法实现未来和素数:
Task<T>
是未来(或单位回归未来的任务),TaskCompletionSource<T>
是一个承诺,也显示在帖子here中。这意味着我们可以简单地search C#替换未来和承诺,然后将它们转换为C ++ - Cli。
在我的回答中,我只展示了如何翻译和使用Task
以及内置代表的一些要点。任务本身很简单:
#include "stdafx.h"
using namespace System;
using namespace System::Threading::Tasks;
public ref class MyActions
{
public:
MyActions()
{
// lambdas are not allowed for managed class so we use built in delegates
auto t = gcnew Task(gcnew Action<Object^>(task1),this);
}
public:
static void task1(Object^ o)
{
// TODO:
printf("Hello World! [c++-cli] and [win32]");
}
};
正如您所看到的,C ++ - Cli语法与c#非常相似,并且您仍然可以使用大多数旧版本的#c; C ++。
注意:我们仍然应该将类定义和实现分开(myactions.h和myactions.cpp)
答案 1 :(得分:0)
C ++ / CLI不允许包含任何标准标题<mutex>
,<future>
,<thread>
&amp; <condition_variable>
(VS2017中的BTW,您可以使用<atomic>
)。它也不允许使用微软提供的concurrency runtime。
由于您使用的是C ++ / CLI,我认为可移植性不是问题。 我的建议是你在windows API周围使用瘦包装器来推送自己的互斥锁,condition_variable,future和promise。
前段时间我写了一些代码就是这样做的。它并不像听起来那么难。
注意:
#include <windows.h>
class srwlock
{
SRWLOCK _lk{};
public:
void lock()
{
AcquireSRWLockExclusive(&_lk);
}
void unlock()
{
ReleaseSRWLockExclusive(&_lk);
}
void lock_shared()
{
AcquireSRWLockShared(&_lk);
}
void unlock_shared()
{
ReleaseSRWLockShared(&_lk);
}
SRWLOCK* native_handle()
{
return &_lk;
}
srwlock() = default;
srwlock(const srwlock&) = delete;
srwlock& operator=(const srwlock&) = delete;
srwlock(srwlock&&) = delete;
srwlock& operator=(srwlock&&) = delete;
};
template <typename _Lk>
class unique_srwlock
{
_Lk& _lk;
friend class srwcondition_variable;
public:
void lock()
{
_lk.lock();
}
void unlock()
{
_lk.unlock();
}
unique_srwlock(_Lk& lk) : _lk(lk)
{
_lk.lock();
};
~unique_srwlock()
{
_lk.unlock();
};
unique_srwlock(const unique_srwlock&) = delete;
unique_srwlock& operator=(const unique_srwlock&) = delete;
unique_srwlock(unique_srwlock&&) = delete;
unique_srwlock& operator=(unique_srwlock&&) = delete;
};
enum class srcv_status
{
timeout, no_timeout
};
class srwcondition_variable
{
CONDITION_VARIABLE _cv{};
public:
void wait(srwlock& lk)
{
VERIFY_TRUE(SleepConditionVariableSRW(&_cv, lk.native_handle(), INFINITE, 0));
}
void wait(unique_srwlock<srwlock>& lk)
{
VERIFY_TRUE(SleepConditionVariableSRW(&_cv, lk._lk.native_handle(), INFINITE, 0));
}
srcv_status wait_for(unique_srwlock<srwlock>& lk, const std::chrono::milliseconds& timeout_duration)
{
auto val = SleepConditionVariableSRW(&_cv, lk._lk.native_handle(), static_cast<DWORD>(timeout_duration.count()), 0);
if (val != 0)
{
return srcv_status::no_timeout;
}
else
{
if (GetLastError() == ERROR_TIMEOUT)
{
return srcv_status::timeout;
}
else
{
throw std::runtime_error("wait_for unexpected return value in SleepConditionVariableSRW");
}
}
}
void notify_one()
{
WakeConditionVariable(&_cv);
}
void notify_all()
{
WakeAllConditionVariable(&_cv);
}
srwcondition_variable() = default;
srwcondition_variable(const srwcondition_variable&) = delete;
srwcondition_variable& operator=(const srwcondition_variable&) = delete;
srwcondition_variable(srwcondition_variable&&) = delete;
srwcondition_variable& operator=(srwcondition_variable&&) = delete;
};
class bad_srfuture : public std::runtime_error
{
public:
bad_srfuture(const char* msg) : std::runtime_error(msg) {}
};
inline void throw_bad_srfuture(bool isValid)
{
if (!isValid)
{
throw bad_srfuture("no state");
}
}
#ifdef _DEBUG
#ifndef FUTURE_THROW_ON_FALSE
#define FUTURE_THROW_ON_FALSE(stmt) throw_bad_srfuture(stmt);
#endif
#else
#ifndef FUTURE_THROW_ON_FALSE
#define FUTURE_THROW_ON_FALSE(stmt) __noop
#endif
#endif
enum class srfuture_status
{
deffered, ready, timeout
};
namespace private_details
{
template <typename T>
class future_shared_state
{
public:
void wait() const
{
// wait until there is either state or error
unique_srwlock<srwlock> lk(_cs);
while (!_state && !_error)
{
_available.wait(lk);
}
}
srfuture_status wait_for(const std::chrono::milliseconds& timeout_duration)
{
// wait until there is either state or error
unique_srwlock<srwlock> lk(_cs);
while (!_state && !_error)
{
auto cv_status = _available.wait_for(lk, timeout_duration);
if (cv_status == srcv_status::timeout)
{
return srfuture_status::timeout;
}
}
return srfuture_status::ready;
}
T& get()
{
if (_state) return *_state;
if (_error) std::rethrow_exception(_error);
throw std::logic_error("no state nor error after wait");
}
template <typename U>
void set_value(U&& value)
{
unique_srwlock<srwlock> lk(_cs);
if (_state.has_value() || _error != nullptr)
{
throw bad_srfuture("shared state already set");
}
_state.emplace(std::forward<U>(value));
_available.notify_all();
}
void set_exception(std::exception_ptr e)
{
unique_srwlock<srwlock> lk(_cs);
if (_state.has_value() || _error != nullptr)
{
throw bad_srfuture("shared state already set");
}
_error = e;
_available.notify_all();
}
private:
mutable srwlock _cs; // _state protection
mutable srwcondition_variable _available;
std::optional<T> _state;
std::exception_ptr _error;
};
} // namespace private_details
template <typename T> class srpromise;
template <typename T>
class srfuture {
public:
srfuture() noexcept = default;
~srfuture() = default;
srfuture(srfuture const& other) = delete;
srfuture& operator=(srfuture const& other) = delete;
srfuture& operator=(srfuture&& other) noexcept = default;
srfuture(srfuture&&) noexcept = default;
T get()
{
// get is assumed to be called from a single thread.
// step 1: pass the _shared_state to the current thread waiter (invalidate)
// (other threads calling get() will result in undefined behaviour as _shared_state will be nullptr
auto shared_state = std::move(_shared_state);
FUTURE_THROW_ON_FALSE(shared_state != nullptr);
// step 2: safely wait for the shared state to fulfill
shared_state->wait();
// shared state is fulfilled and no exception is set.
// step 3: move / copy the state:
return std::move(shared_state->get()); // https://stackoverflow.com/questions/14856344/when-should-stdmove-be-used-on-a-function-return-value
}
bool valid() const noexcept
{
return _shared_state != nullptr;
}
void wait() const
{
// The behavior is undefined if valid() == false before the call to this function.
FUTURE_THROW_ON_FALSE(valid());
_shared_state->wait();
}
srfuture_status wait_for(const std::chrono::milliseconds& timeout_duration) const
{
FUTURE_THROW_ON_FALSE(valid());
_shared_state->wait_for(timeout_duration);
}
private:
std::shared_ptr<private_details::future_shared_state<T>> _shared_state = nullptr;
friend class srpromise<T>;
srfuture(const std::shared_ptr<private_details::future_shared_state<T>>& shared_state) : _shared_state(shared_state) {}
srfuture(std::shared_ptr<private_details::future_shared_state<T>>&& shared_state) : _shared_state(std::move(shared_state)) {}
};
template <typename T>
class srpromise
{
public:
srpromise() : _shared_state(std::make_shared<private_details::future_shared_state<T>>()) {}
srpromise(srpromise&& other) noexcept = default;
srpromise(const srpromise& other) = delete;
srpromise& operator=(srpromise&& other) noexcept = default;
srpromise& operator=(srpromise const& rhs) = delete;
~srpromise() = default;
void swap(srpromise& other) noexcept
{
_shared_state.swap(other._shared_state);
}
srfuture<T> get_future()
{
return { _shared_state };
}
void set_value(const T& value)
{
_shared_state->set_value(value);
}
void set_value(T&& value)
{
_shared_state->set_value(std::move(value));
}
void set_exception(std::exception_ptr p)
{
_shared_state->set_exception(std::move(p));
}
private:
std::shared_ptr<private_details::future_shared_state<T>> _shared_state = nullptr;
};