65.9K
CodeProject 正在变化。 阅读更多。
Home

通用任务/工作者实现

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.67/5 (2投票s)

2011 年 5 月 1 日

CPOL

4分钟阅读

viewsIcon

17126

downloadIcon

548

一个通用的任务/工作者实现,为您的对象提供异步“即发即弃”机制

引言

以下文章讨论了一个简单的任务/工作者实现。它遵循为您的应用程序/对象提供异步“即发即弃”风格机制的思路。假设读者了解以下 TR1 概念;可调用对象 (std::tr1::function), 函数绑定 (std::tr1::bind)。如果没有这些先决条件,这篇文章可能会令人困惑。

背景

我遇到的大量涉及线程的代码通常表现出对象与线程之间的“is-a”关系。这基本上意味着对象“是一个”线程。在某些情况下,实现对象与其线程之间的“has-a”关系是有意义的。从表面上看,两者似乎都实现了相同的功能,但后者提供了一种更模块化的方法。

传统的编码实践包括,从某个“CThread”类派生您的对象,并实现某种“Run()”函数,该函数封装了需要完成的异步工作量。在大多数情况下,“is-a”方法可以奏效,但如果您能将两者分离呢?像往常一样设计一个对象,为其编写代码,然后将异步功能附加到对象中的任何函数。

传统用法

class threaded_object: public my_base_thread_class
{
    public:

    threaded_object(){};
    ~threaded_object(){};

    protected:

    // This would be the overloaded function from your base class
    // that needs to be implemented. This represents the work performed
    // by the worker.

    virtual int run()
    {
    /* do some work */
    return 0;
    }
}

用法将是

threaded_object my_object;
my_object.create_thread(); >-- This would create the thread and call the Run() function. 

让我们看看如何使用通用任务/工作者实现以稍有不同的方式完成此操作。通用任务/工作者对象是一个简单的存根,它在单独的线程上执行可调用对象,表示工作量。该类在“utility”命名空间中呈现,称为“generic_worker”,它可以执行的可调用对象的类型由函数类型“utility::generic_worker_task”表示。

namespace utility
{
    // The template class
    template<t_fn>
    class generic_worker_t

    // This represents the type of callable object ( the quantum of work ) 
    // that the generic_worker class
    // can execute
    typedef std::tr1::function<void()>generic_worker_task;

    // Specialized generic_worker
    typedef generic_worker_t<generic_worker_task>generic_worker;
}

generic_worker”对象期望传入的可调用对象属于类型“generic_worker_task”,它不接受任何参数,也不返回任何内容。您类中的任何函数/成员函数都可以使用称为“bind”(std::tr1::bind)的操作转换为可调用对象。bind操作返回一个可调用对象,该对象具有已经绑定到该函数的预定义参数。唯一的问题是返回值。您的类中的函数可能会返回值,并且从这些函数创建的可调用对象不能包含在“generic_worker_task”类型对象中,因为它具有返回值。为此,您可以轻松地将“generic_worker_t”模板化以接受适当的可调用对象类型。例如,如果您的函数返回“int”,您可以如下所示专门化“generic_worker_t

typedef std::tr1::function<int()>generic_worker_task_int;

// Specialized generic_worker
typedef generic_worker_t<generic_worker_task_int>generic_worker_int;

Using the Code

假设您有一个以下形式的类

class my_object
{
public:

    int function_a();
    int function_b();
    int function_c();
}

假设这些函数中的每一个都需要很长时间才能完成。例如,想象一下您想直接从 GUI 线程调用这些函数,如果您这样做,它会导致消息循环停止传递消息并阻塞,从而使 UI 无响应,因此需要将此工作卸载到另一个线程。所举的例子只是众多用例之一。

步骤 1:创建您的模板化通用工作者对象。在这种情况下,所有函数都返回int,因此generic_worker对象将专门化为可调用对象,该对象不接受任何参数并返回一个int

typedef std::tr1::function<int()>generic_worker_task_int;

// Specialized generic_worker
typedef generic_worker_t<generic_worker_task_int>my_generic_worker;

步骤 2:将此工作者包含在您的主对象中

class my_object
{
public:

    int function_a();
    int function_b();
    int function_c();

protected:

    my_generic_worker async_obj;
}

步骤 3:为异步行为创建存根,其中async_[函数名]表示该函数的非阻塞或异步版本。仅为需要异步行为的那些函数创建存根。

class my_object
{
public:

    // async stubs
    int async_function_a(int arg1);
    int async_function_b(bool arg1);

    // actual functions
    int function_a(int arg1);
    int function_b(bool arg1);
    int function_c();
}

步骤 4:实现存根。这是您将使用 bind 操作来绑定函数参数的地方。

根据您希望如何处理传入的可调用对象指针,您可以调用不删除传入的可调用对象指针的“do_work”函数,或删除传入的可调用对象的“do_work_and_clean()”函数。

int my_object::async_function_a(int arg1)
{
    generic_worker_task_int* p = new( generic_worker_task_int );
    if( p )
    {
        *p = std::tr1::bind(&my_object::function_a,this,arg1);
        async.do_work_and_clean(p, THREAD_PRIORITY_NORMAL);
    }
    return 1;
}

int async_function_b(bool arg1)
{
    generic_worker_task_int* p = new( generic_worker_task_int );
    if( p )
    {
        *p = std::tr1::bind(&my_object::async_function_b,this,arg1);
        async.do_work_and_clean(p, THREAD_PRIORITY_NORMAL);
    }

    return 1;
};

步骤 5:调用异步存根现在将异步执行该方法。

my_object instance_of_my_object;
instance_of_my_object.async_function_a(1);

async_版本的调用返回给调用者,工作者线程执行实际任务。由对象开发人员设计父对象进行多线程处理,并处理并发问题等。“generic_worker”不会遗弃任何正在运行的任务,并且会在其所有任务线程完成之前等待销毁。

generic_task”对象可能需要同步,需要并发的部分用注释标记。通过添加锁/关键节来保护这些部分可能是有意义的。

历史

  • 2010 年 4 月 28 日 - 修订版 1
© . All rights reserved.