Как выполнить метод в другом потоке? - PullRequest
9 голосов
/ 24 ноября 2010

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

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

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

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

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

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

Ответы [ 5 ]

2 голосов
/ 24 ноября 2010

Моя стандартная ссылка для этой проблемы здесь .

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

Как заметил @Джон, здесь используется Boost.Thread.

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

1 голос
/ 25 ноября 2010

ИМХО, если вы хотите разделить выполнение метода и контекст потока, вы должны использовать Active Object Pattern (AOP)

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

Подробную информацию можно найти здесь

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

1 голос
/ 24 ноября 2010

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

Определите классы, соответствующие каждой функциональности, предоставляемой вашим сервером. Каждый из этих классов реализует функцию с именем 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 голосов
/ 25 ноября 2010

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

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

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(); }
  };

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

0 голосов
/ 24 ноября 2010

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

...