Хранение и последующий вызов функции-члена неизвестного класса - PullRequest
3 голосов
/ 23 мая 2011

Я пытаюсь создать пул потоков, который может запускать функции из неизвестных классов. Я не хочу создавать нечленов в качестве прокси. Мне удалось создать класс рабочих пулов и рабочих потоков, а также структуру задач. Все это шаблоны.

// ThreadPool.h
/* Threadpool creates N WorkerThreads (each worker has a ptr to the creating pool), 
    these block until a task is ready then call ThreadPool::doTask() */
template<class T>
struct Task {
    Task() : func(0), inst(0) { }

    Task(boost::function<void(T*)> function, T* instance) : func(0), inst(0) {
        func = function;
        inst = instance;
    }

    void operator()() {
        Task::func(inst);
    }

    T* inst;
    boost::function<void(T*)> func;
};

template<class T>
class ThreadPool {
    template<class T> friend class WorkerThread;
public:

    void addTask(Task<T> task) {
        ... // Some stuff
    }

    bool doTask() {
        Task<T> task;

        ... // Gets a task from std::queue

        // Check the task actually exists!
        if(task.func && task.inst) {
            // Do the task
            (task)();
        }
    }
private:
    std::queue<Task<T>> mTasks;
};

Как есть, этот код работает, при условии, что я определяю класс для ThreadPool и Task. Но я хочу иметь возможность вызывать членов неизвестных типов классов. Я считал пустой ptr, но я не мог найти способ преобразовать это в действительный экземпляр ptr. Я также изучил boost :: mem_fun, но изо всех сил пытался справиться с этим.

Я кратко прочитал о C ++ 0x и, насколько я понимаю, это должно облегчить решение моей проблемы, но я хотел бы решить это до этого, если это вообще возможно.

Ответы [ 2 ]

3 голосов
/ 23 мая 2011

Зачем вообще использовать T * вместо boost::function<void ()>?

Таким образом, вы можете использовать бесплатные функции, а также функции-члены, и вы можете упростить свой код.

Задача для члена в экземпляре класса X может быть поставлена ​​в очередь следующим образом:

poll.add(boost::bind(&X::member, x_instance, other_arguments));

В вашем коде нет приведений и шаблонов.

Обновление:

Используйте boost :: function вместо вашего класса Task. Затем вам просто нужно отслеживать экземпляры и вызывать их по мере необходимости. Например:

class TaskQueue {
    std::deque<boost::function<void ()> > m_tasks;

public:
    void add(boost::function<void ()> const& f) { m_tasks.push_back(f); }
    bool has_task() const { return !m_tasks.empty(); }
    void do_task() {
        m_tasks.front()();
        m_tasks.pop_front();
    }
};

int example_enqueue(TaskQueue* tq) {
    boost::shared_ptr<RandomClass> rc(new RandomClass);
    tq->add(boost::bind(&RandomClass::method, rc, arg_1, arg_whatever));
}

Обратите внимание, что, комбинируя этот метод с boost :: shared_ptr, вы получаете автоматическое уничтожение ваших объектов, когда функция выходит из области видимости, если это последняя ссылка. Это делает жизнь намного проще.

0 голосов
/ 23 мая 2011

Пустота * будет работать.Вам просто нужно сделать сильный reinterpret_cast.Но я бы не стал использовать это решение.В Boost есть несколько способов создания объектов-функторов: http://www.boost.org/doc/libs/1_46_1/doc/html/function.html

...