c# – 如何取消执行非托管C外部例程的任务
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了c# – 如何取消执行非托管C外部例程的任务,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含4997字,纯文字阅读大概需要8分钟。
内容图文
![c# – 如何取消执行非托管C外部例程的任务](/upload/InfoBanner/zyjiaocheng/787/bc83bbc113af4c8fb6fcf0ed51036ec5.jpg)
我正在尝试修复C#异步代码,启动在非托管C例程中编写的外部dll中执行的可取消操作.
有没有办法在创建时使用传递给Task的Cancellation Token取消任务,如果用户委托调用外部非托管C例程?
据我所知,任务取消涉及用户代表与请求取消的代码之间的合作.成功取消涉及请求代码调用CancellationTokenSource.Cancel方法,并且用户委托及时终止操作,方法是在他注意到已经提出取消请求时通过简单地从委托返回(通过轮询CancellationToken.IsCancellationRequested方法)或使用CancellationToken.ThrowIfCancellationRequested方法抛出OperationCanceledException. (cf http://msdn.microsoft.com/en-us/library/dd997396%28v=vs.110%29.aspx)
这两种方式涉及由用户委托执行的非托管C例程通过接收CancellationToken作为参数并通过定期调用其IsCancellationRequested和/或ThrowIfCancellationRequested方法来进行协作.
是否可以通过非托管外部C例程执行此操作?
如果没有,当请求代码请求取消时,是否有办法强制终止执行用户委托的任务(执行非托管c例程)?
下面是我正在尝试修复的混合C#/ C Cli / Unmanaged C代码的示例(摘录),以便能够取消C非托管代码部分中用户委托执行的操作:
FrmDemo.cs:———————————————- —————————
public class FrmDemo : Form
{
private CliClass m_CliObject;
private System.Threading.CancellationTokenSource m_Cts;
private System.Threading.CancellationToken m_Ct;
private void FrmDemo_Load(object sender, EventArgs e)
{
// Creating the external CliObject:
this.m_CliObject = new NSDemo.CliClass();
...
}
// Event handler of the button starting the cancelable asynchrone operation:
private async void btnStart_Click(object sender, EventArgs e)
{
m_Cts = new System.Threading.CancellationTokenSource();
m_Ct = m_Cts.Token;
await Task.Factory.StartNew(() =>
{
// Launching a cancelable operation performed by a managed C++Cli Object :
this.m_CliObject.DoSomething(); // How to eventually pass the CancellationToken m_ct to the m_CliObject ?
}, m_ct);
...
}
//Event handler of the cancel button:
private void btnCancel_Click(object sender, EventArgs e)
{
// Requesting cancellation:
m_Cts.Cancel();
// (Or alternatively, how to eventually force the termination of the async Task without collaboration from it ?)
}
CliClass.h:———————————————- ——-
#include "DemoCore.h"
using namespace System;
using namespace System::Runtime::InteropServices;
using namespace cli;
namespace NSDemo
{
public ref class CliClass
{
public:
CliClass();
~CliClass();
void DoSomething()
{
// Performing the operation in the unmanaged coreObject:
_coreObject->DoSomething();
}
private:
UNSDemo::CoreClass *_coreObject;
bool _disposed;
};
}
CliClass.cpp:——————————————
namespace NSDemo
{
CliClass::CliClass()
{
_coreObject = new UNSDemo::CoreClass(...);
....
}
CliClass::~CliClass()
{
if (_disposed)
return;
if (_coreObject != nullptr) {
delete _coreObject;
_coreObject = nullptr;
}
_disposed = true;
GC::SuppressFinalize(this);
}
CoreClass.h-----------------------------------------------------------------
namespace UNSDemo {
class __declspec(dllexport) CoreClass {
public:
ScanningCore();
~ScanningCore();
void DoSomething();
private:
...
};
}
CoreClass.cpp:———————————————- ——————————
#include "CoreClass.h"
namespace UNSDemo {
CoreClass::CoreClass()
{
...
}
CoreClass::~CoreClass()
{
...
}
// Method actually performing the cancelable operation:
void CoreClass::DoSomething()
{
// Main loop of the unmanaged cancelable operation:
while (...) {
...
// How to check the cancellation request from here ? (How to access the CancellationToken ?)
// and if cancellation is requested, how to eventually throw the OperationCanceledException ?
}
}
}
感谢您的任何帮助.
解决方法:
如果你正在处理纯粹的非托管代码,它不知道CancellationToken类,所以你不能像托管代码那样传递它.
我要做的是声明你的非托管方法获取指向布尔值的指针,如果布尔值设置为true,则让非托管代码自行中止.在您的包装器中,使用CancellationToken.Register注册一个回调,该回调将取消CancellationToken时将Boolean设置为true.
这听起来很简单,但它有点复杂,因为您需要一个托管事件处理程序,它可以访问您允许获取地址的布尔值.
public ref class CancelableTaskWrapper
{
private:
bool* isCanceled;
void (*unmanagedFunctionPointer)(bool*);
void Canceled() { if (isCanceled != nullptr) *isCanceled = true; }
public:
CancelableTaskWrapper(void (*unmanagedFunctionPointer)(bool*))
{
this->unmanagedFunctionPointer = unmanagedFunctionPointer;
isCanceled = new bool;
}
~CancelableTaskWrapper() { if (isCanceled != nullptr) delete isCanceled; isCanceled = nullptr; }
!CancelableTaskWrapper() { if (isCanceled != nullptr) delete isCanceled; isCanceled = nullptr; }
void RunTask(CancellationToken cancelToken)
{
*isCanceled = false;
CancellationTokenRegistration reg = cancelToken.Register(
gcnew Action(this, &CancelableTaskWrapper::Canceled));
unmanagedFunctionPointer(isCanceled);
}
};
void someUnmanagedFunction(bool* isCanceled)
{
doSomethingLongRunning();
if(*isCanceled) return;
doSomethingLongRunning();
}
>因为isCanceled是指向bool的指针,所以它在堆上.因此,我们被允许传递一个指向它的指针,而不需要做任何特殊的事情(例如,固定托管对象).
> CancellationTokenRegistration实现IDisposable,当reg超出范围时,它将自动取消注册. (你可以用C#中的using语句来完成这个.)
免责声明:我现在不在编译器中;可能存在语法错误.
内容总结
以上是互联网集市为您收集整理的c# – 如何取消执行非托管C外部例程的任务全部内容,希望文章能够帮你解决c# – 如何取消执行非托管C外部例程的任务所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。