往期教程
如果觉得写的可以,请给一个点赞+关注支持一下
观看之前请先看,往期的两篇博客教程,否则这篇博客没办法看懂
-
workFlow c++异步网络库编译教程与简介
-
C++异步网络库workflow入门教程(1)HTTP任务
-
C++异步网络库workflow系列教程(2)redis任务
简介
首先,workflow是任务流
的意思,在workflow中万物皆为任务流.任务流分为以下两种
串联:
就像链表一样,前面的任务执行完了后执行后面的并联:
可以理解为开了多个线程,并发执行任务
示例代码
首先,还是老规矩,先看代码示例,我会将所有新出现的成员一一进行介绍
#include <workflow/WFFacilities.h>
void seriesCallback(const SeriesWork *series){
fprintf(stderr,"series callback , free pkey\n");
std::string *pkey = static_cast<std::string *>(series->get_context());
delete pkey;
}
void callback(WFRedisTask *redisTask){
protocol::RedisRequest *req = redisTask->get_req();
protocol::RedisResponse *resp = redisTask->get_resp();
int state = redisTask->get_state();
int error = redisTask->get_error();
protocol::RedisValue value;//value对象专门用来存储redis任务的结果
switch (state){
case WFT_STATE_SYS_ERROR:
fprintf(stderr,"system error: %s\n", strerror(error));
break;
case WFT_STATE_DNS_ERROR:
fprintf(stderr,"dns error: %s\n", gai_strerror(error));
break;
case WFT_STATE_SUCCESS:
resp->get_result(value);
if(value.is_error()){
fprintf(stderr,"redis error\n");
state = WFT_STATE_TASK_ERROR;
}
break;
}
if (state != WFT_STATE_SUCCESS){
fprintf(stderr, "Failed\n");
return;
}
else{
fprintf(stderr, "Success!\n");
}
std::string cmd;
req->get_command(cmd);
if(cmd=="SET"){
//firstTask的基本工作做完了
//创建新任务,把新任务加入到本序列的末尾
fprintf(stderr,"first task callback begins\n");
std::string *pkey = static_cast<std::string *>(redisTask->user_data);
WFRedisTask *secondTask = WFTaskFactory::create_redis_task("redis://127.0.0.1:6379",0,callback);
protocol::RedisRequest *req = secondTask->get_req();
req->set_request("GET",{*pkey});
SeriesWork* series = series_of(redisTask);
series->set_context(static_cast<void *>(pkey));
series->set_callback(seriesCallback);
series->push_back(secondTask);
fprintf(stderr,"first task callback ends\n");
}
else{
//secondTask的基本工作做完了
fprintf(stderr,"second task callback begins\n");
fprintf(stderr, "redis request, cmd = %s\n", cmd.c_str());
if (value.is_string()){
fprintf(stderr, "value is a string, value = %s\n", value.string_value().c_str());
}
else if (value.is_array()){
fprintf(stderr, "value is string array\n");
for (size_t i = 0; i < value.arr_size(); ++i){
fprintf(stderr, "value at %lu = %s\n", i, value.arr_at(i).string_value().c_str());
}
}
fprintf(stderr,"second task callback ends\n");
}
}
int main(){
//创建redis任务
//std::string key = "43key1";
std::string * pkey = new std::string("43key2");
WFRedisTask *firstTask = WFTaskFactory::create_redis_task("redis://127.0.0.1:6379",0,callback);
//设置redis任务的属性
protocol::RedisRequest *req = firstTask->get_req();
req->set_request("SET",{*pkey, "200"});
firstTask->user_data = static_cast<void *>(pkey);
//启动redis任务
firstTask->start();
}
示例剖析
- 首先我们先看见main函数中第77行
firstTask->user_data
,如下是该成员的源码实现截图,为一个void*指针
,通过变量名我们可以知道这是用来存储用户上下文的变量,可以在响应回调函数中将数据取出来进行使用(如43行中取出使用)
任务流
series_of(redisTask)
函数可以通过任务流节点
获取到该任务节点所属的任务流的指针(在main函数中调用的firstTask->start();
便是创建了一个任务流),set_context()
与上面的user_data
类似,不过set_context
设置的生存周期在整个任务流的生存周期,而user_data
的生存周期只在所属的任务流节点
的生存周期set_callback()
用来设置该任务流
的清理回调函数,调用时机在该任务流所有任务节点全部执行完毕之后series->push_back(secondTask):
将secondTask
这个任务添加在任务流的末尾节点
代码执行流程梳理
- main函数中设置了一个
redis
任务,任务将执行"SET 43key2 200"
这个指令 - 在
callback
回调函数中,找到该任务所属的任务流,并创建一个新的任务执行"GET 43key2"
这个命令,并将这个任务插在任务流后面, - 在
callback
回调函数中,执行53行
开始的代码