Chinaunix首页 | 论坛 | 博客
  • 博客访问: 875245
  • 博文数量: 366
  • 博客积分: 10267
  • 博客等级: 上将
  • 技术积分: 4290
  • 用 户 组: 普通用户
  • 注册时间: 2012-02-24 14:04
文章分类

全部博文(366)

文章存档

2012年(366)

分类: 系统运维

2012-03-25 18:39:03

在上一篇文章中,我介绍一些在VS中C++异步编程的简单概念和语法。这篇,我们讨论一下异步编程中取消操作的概念。

取消操作:

取消一个正在进行的task,方式大概分两种,一种是从内部取消,另外一种是从外部取消。

我们通过cancel_current_task 去从内部取消这个task

#include

#include
#include
#include
using namespace Concurrency;
using namespace std;

void do_work()
{
// Simulate work.
wcout << L"Performing work..." << endl;
wait(250);
}

int _tmain(int argc, _TCHAR* argv[])
{
wcout << L"Creating task..." << endl;
task<void> t([]() {
bool moreToDo = true;
int i=0;
while (moreToDo)
{
i++;
if(i==4)
{
wcout<"In cancellation"<// call this function to cancel
cancel_current_task();
}
do_work();
}
});

wait(1000);
}

这里要说明一点的是,在我们声明这个task之后,我们并没有调用.wait() 或者.get() 去执行他。只是调用了wait(1000);这个task就被执行了。这个是因为,wait(1000)这个函数,表面上是让当前的线程休息1000毫秒,但是他会激发后台scheduled状态的task,当这个task声明之后,他的状态就是scheduled,当我们在主线程调用wait()的方法,之前声明的task就会被激发和执行,所以我们不需要调用.wait()或者.get()去执行他。

如果我们想从外部取消这个task,我们需要传一个token给这个task,然后我们通过 这个方法去取消这个task

wcout << L"Creating task..." << endl;


cancellation_token_source cts;
auto token=cts.get_token();
task<void> t([]() {

bool moreToDo = true;
while (moreToDo)
{
// Simulate work.
do_work();
}
},token);

wait(1000);
cts.cancel();
// Wait for the task to cancel.
wcout << L"Waiting for task to complete..." << endl;
t.wait();

wcout << L"Done." << endl;
return 0;

在外部取消这个task的过程中,我们想在内部获得取消这个动作的信号。我们可以通过 函数去获取

task<void> t([]() {

bool moreToDo = true;
while (moreToDo)
{
// Check for cancellation.
if (is_task_cancellation_requested()) {

wcout << L"Get the cancel event" << endl;
// Cancel the current task.
cancel_current_task();

// You must end this task in front line or in this line
moreToDo = false;

}
else {
// Perform work.
do_work();
}
}
}, token);

// Wait for one second and then cancel the task.
wait(1000);

wcout << L"Canceling task..." << endl;
cts.cancel();

// Wait for the task to cancel.
wcout << L"Waiting for task to complete..." << endl;
t.wait();


这里要注意的是, 当我们调用cts.cancel()的时候, 返回true,但是这个task并没有被取消,我们必须要在task里面手动调用cancel_current_task,或者通过其他办法让函数结束。如果我们不判断 就不需要我们在task内部手动取消。


我们还可以注入callback 函数,在我们尝试外部取消的时候。

cancellation_token_source cts;
auto token=cts.get_token();
cancellation_token_registration cookie;
cookie=token.register_callback([](){ wcout << L"In cancellation callback..." << endl;});
task<void> t([]() {

bool moreToDo = true;
while (moreToDo)
{
// Simulate work.
do_work();
}
},token);

wait(1000);
cts.cancel();

token.deregister_callback(cookie);

以上的例子都是基于while循环的,我认为这样可以便于理解。同样,我们也可以用event,在Concurrency namespace里面,系统事件已经被封装成event Class (Concurrency Runtime) 这个类,有set wait 等方法便于使用。下面的例子就是基于event 和callback函数的


// task-cancellation-callback.cpp
// compile with: /EHsc
#include
#include

using namespace Concurrency;
using namespace std;

int wmain()
{
cancellation_token_source cts;
auto token = cts.get_token();

// An event that is set in the cancellation callback.
event e;

cancellation_token_registration cookie;
cookie = token.register_callback([&e, token, &cookie]() {

wcout << L"In cancellation callback..." << endl;
e.set();

// Although not required, demonstrate how to unregister
// the callback.
token.deregister_callback(cookie);
});

wcout << L"Creating task..." << endl;

// Create a task that waits to be canceled.
task<void> t([&e]() {
e.wait();
}, token);

// Cancel the task.
wcout << L"Canceling task..." << endl;
cts.cancel();

// Wait for the task to cancel.
t.wait();

wcout << L"Done." << endl;

}

这里还要注意deregister_callback,传入参数必须是引用类型。

最后关于取消操作,还要说一点就是如何给一个parallel_for 添加取消动作,首先,这个函数本是是没有支持取消操作的,我们要给他外面套一层task,通过取消外面的task,来取消里面的parallel_for。

int wmain()
{
cancellation_token_source cts;

//
// Run a parallel_for loop in a call to run_with_cancellation_token.
wcout << L"Running a task with a cancellation token..." << endl;
run_with_cancellation_token([cts] {

// For illustration, cancel the overall operation on the third
// iteration of a parallel loop. The parallel_for call implicitly
// inherits the cancellation token of the parent task.
long counter = 0;
parallel_for(0, 100, [cts, &counter](int n) {
if (InterlockedIncrement(&counter) == 3)
{
wstringstream ss;
ss << L"Canceling..." << endl;
wcout << ss.str();

cts.cancel();
}

wstringstream ss;
ss << L"In iteration " << n << L" of parallel_for..." << endl;
wcout << ss.str();
});
}, cts.get_token());

wcout << L"Done." << endl;

}

阅读(682) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~