2010-11-24 5 views
8

Я ищу решение этой проблемы на C или C++.
Редактировать: уточнить. Это на Linux-системе. Решения, специфичные для Linux, абсолютно прекрасны. Кросс-блафор не вызывает беспокойства.Как выполнить метод в другом потоке?

У меня есть служба, которая работает в своей собственной теме. Эта услуга - это класс с несколькими методами, некоторые из которых должны выполняться в потоке собственной службы, а не в потоке вызывающего.

В настоящее время я использую методы-обертки, которые создают структуру с параметрами ввода и вывода, вставляют структуру в очередь и возвращают (если «команда» асинхронна) или дождаться ее выполнения (если «команда» синхронно).

На стороне потока служба просыпается, выталкивает структуру из очереди, вычисляет, что выполнять, и вызывает соответствующий метод.

Эта реализация работает, но добавление новых методов довольно громоздко: определите оболочку, структуру с параметрами и обработчик. Мне было интересно, есть ли более простые способы кодирования такой модели: метод класса, который выполняется в собственном потоке класса, а не в потоке вызывающего.

редактировать - вид заключения:
Кажется, что нет де-факто способ осуществить то, что я спросил, что не предполагает дополнительных усилий кодирования.
Я буду придерживаться того, с чем я столкнулся, он обеспечивает безопасность типа, сводит к минимуму блокировку, позволяет синхронизировать и асинхронные вызовы, а накладные расходы - довольно скромные.
С другой стороны, для этого требуется немного дополнительного кодирования, и механизм отправки может раздуваться по мере увеличения количества методов. Регистрация методов отправки при построении или наличие оберток делают эту работу, похоже, решают проблему, удаляют немного служебных данных и также удаляют некоторый код.

+1

Вы получите предложения, не зависящие от платформы, используя Boost.Thread, но какая платформа? – 2010-11-24 16:34:30

+0

Это на linux. Он не должен быть кросс-платформенным. – amso 2010-11-24 17:26:34

ответ

1

Существует несколько способов достижения этого, в зависимости от сложности, которую вы хотите принять. Сложность кода прямо пропорциональна желаемой гибкости. Вот простой (и довольно хорошо используемый):

Определите классы, соответствующие каждой функциональности, предоставляемой вашим сервером. Каждый из этих классов реализует функцию, называемую execute, и принимает базовую структуру, называемую входными аргументами и выходными аргументами.

Внутри службы регистрируются классы методов во время инициализации. Как только запрос приходит в поток, он будет иметь только два аргумента: Input и Ouput, которые являются базовыми классами для более специализированных аргументов, требуемых разными классами методов.

Затем вы пишете класс обслуживания как простое делегирование, которое принимает входящий запрос и переходит к соответствующему классу метода на основе идентификатора или имени метода (используемого при первоначальной регистрации).

Надеюсь, это имеет смысл, очень хорошим примером такого подхода является XmlRpC++ (реализация XmlRpc на C++, вы можете получить исходный код из sourceforge).

Чтобы резюмировать:

struct Input { 
    virtual ~Input() = 0; 
}; 

struct Ouput { 
    virtual ~Output() = 0; 
}; 

struct MethodInterface { 
    virtual int32_t execute (Input* __input, Output* __output) = 0; 
}; 

// Write specialized method classes and taking specialized input, output classes 
class MyService { 


    void registerMethod (std::string __method_name, MethodInterface* __method); 
    //external i/f 
    int32_t execute (std::string __method, Input* __input, Output* __output); 
}; 

Вы все еще использовать механизм очереди, но вам не нужно будет никаких оберток.

+0

Можете ли вы отформатировать код так, чтобы он воспринимался как таковой, а также читался? Благодаря! Ваше решение выглядит как то, что я делаю сейчас. Мне нужно написать класс-оболочку для каждого метода/функциональности и метод для вызова этой функции извне. Или я неправильно понял ответ? – amso 2010-11-24 17:44:13

2

Эта стандартная ссылка для этой проблемы - here.

Реализация поточно-Queue с помощью условных переменных

Как отмечалось @John, это использует Boost.Thread.

Я был бы осторожен в синхронном случае, описанном здесь. Легко получить первичную проблему, если производитель (отправляющий поток) ждет результата от потребителя (поток услуг). Что произойдет, если вы получите 1000 асинхронных вызовов, заполнив очередь с отставанием, а затем вызовите синхронизацию из каждого из ваших потоков производителей? Ваша система будет «мертва» до тех пор, пока отставание в очереди не исчезнет, ​​освободив этих абонентов синхронизации. Попытайтесь отделить их, используя async, если сможете.

+0

+1, мне понравилась ссылка. – Default 2010-11-24 16:56:45

0

В дополнение к использованию Boost.Thread я бы посмотрел boost :: function и boost :: bind. Тем не менее, кажется справедливым иметь нетипизированные (void) аргументы, переданные целевым методам, и позволить этим методам применять правильный тип (типичная идиома для таких языков, как C#).

+0

boost :: bind работает, чтобы комбинировать функцию с параметрами, но вам по-прежнему нужна некоторая (полиморфная?) Диспетчеризация, потому что компилятор не может решить, что должен вызвать другой поток. – stefaanv 2010-11-24 19:19:17

0

Эй, Радживджи, я думаю, что у вас это перевернуто. Сложность кода обратно пропорциональна пропорционально гибкости. Чем сложнее ваши структуры данных и алгоритмы, тем больше ограничений вы устанавливаете на приемлемых входах и поведении.

К OP: ваше описание кажется совершенно общим и единственным решением, хотя существуют разные кодировки. Простейшие могут вывести класс из:

 
struct Xqt { virtual void xqt(){} virtual ~Xqt(){} }; 

и затем поточно-очереди указателей на Xqt. Затем поток службы просто выставляет очередь на px и вызывает px-> xqt(), а затем удаляет px. Наиболее важным производный класс это один:

 
    struct Dxqt : Xqt { 
    xqt *delegate; 
    Dxqt(xqt *d) : delegate(d) {} 
    void xqt() { delegate->xqt(); } 
    }; 

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

1

ИМХО, если вы хотите, чтобы расцепить выполнение метода и контекста потока, вы должны использовать Активный шаблон объекта (АОП)

Однако, вам нужно использовать ACE Framework, который поддерживает множество операционных систем, например Windows, Linux, VxWorks

подробной информации here

Также Вы можете найти, АОП представляет собой комбинацию команд, прокси и шаблоны наблюдателей, если вы знаете подробности их, вы можете реализовать свой собственный АОП. Надеюсь, это поможет

Смежные вопросы