线程池 | Result、Task类

1.Task类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//任务抽象基类
class Task
{
public:
Task();
~Task() = default;
void exec();
void setResult(Result* res);
//用户可以自定义任意任务类型,从Task继承,重写run方法,实现自定义任务处理
virtual Any run() = 0;

private:
//不用shared是避免了智能指针交叉引用的问题
Result* result_;//Result 的生存周期要长于Task
};

使用时,用户自己定义一个mytask类继承Task类,重写run方法完成自己想要的任务即可。

exec就是用来执行run()方法的一个包装函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//////////Task方法实现
Task::Task():result_(nullptr){}

void Task::exec()
{
if (result_ != nullptr)
{
result_->setVal(run());
}
}

void Task::setResult(Result* res)
{
result_ = res;
}

2.Result类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//实现接收提交到线程池的task任务执行完后的返回值类型Result
class Result
{
public:
Result(std::shared_ptr<Task> task, bool isValid = true);
~Result()=default;

//setVal方法,获取任务执行完的返回值的
void setVal(Any any);

//get方法,用户调用这个方法获取task 的返回值
Any get();

private:
Any any_;//存储任务的返回值
Semaphore sem_;//线程通信的信号量
std::shared_ptr<Task> task_;//指向对应获取返回值的任务对象
std::atomic_bool isValid_;//表示Result是否有效
};

这个类用来接收对应task_任务结束后的返回值的,一个Task对象对应一个Result对象,Any对象作为类内成员承接具体的返回值。setVal方法是把返回值存储到Result对象的any上,get方法是用户获取task返回值的方法,就是把any的值返回给用户。

值得注意的是,加入了信号量来控制是否完成了任务,如果任务没有完成,会在get方法处阻塞,等待任务完成。

Any不支持拷贝构造所以用move来进行赋值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
///////////Result方法的实现
Result::Result(std::shared_ptr<Task> task, bool isValid)
:isValid_(isValid),task_(task)
{
task_->setResult(this);
}

Any Result::get()//用户调用的
{
if (!isValid_)
{
return "";
}
sem_.wait();//task任务如果没有执行完,这里会阻塞用户线程
return std::move(any_);
}


void Result::setVal(Any any)//
{
//存储task的返回值
this->any_ = std::move(any);
sem_.post();//已经获取了任务的返回值,增加信号量资源
}

这两者是耦合的,一个Task对应一个Result