ThreadPool с использованием ASIO — выход из потока, задача не выполнена

Я пишу класс ThreadPool в C ++, используя Boost ASIO. Ниже приведен код, который я написал до сих пор:

Класс ThreadPool

    using namespace std;
using namespace boost;

class ThreadPoolClass {
private:

/* The limit to the maximum number of threads to be
* instantiated within this pool
*/
int maxThreads;
/* Group of threads in the Pool */
thread_group threadPool;

asio::io_service asyncIOService;

void _Init()
{
maxThreads = 0;
}
public:
ThreadPoolClass();
ThreadPoolClass(int maxNumThreads);
ThreadPoolClass(const ThreadPoolClass& orig);
void CreateThreadPool();
void RunTask(JobClass * aJob);
virtual ~ThreadPoolClass();

};
ThreadPoolClass::ThreadPoolClass() {
_Init();
}ThreadPoolClass::ThreadPoolClass(int maxNumThreads) {
_Init();
maxThreads = maxNumThreads;
}

void ThreadPoolClass::CreateThreadPool() {

asio::io_service::work work(asyncIOService);

for (int i = 0; i < maxThreads; i++) {
cout<<"Pushed"<<endl;
threadPool.create_thread(bind(&asio::io_service::run, &asyncIOService));
}
}

void ThreadPoolClass::RunTask(JobClass * aJob) {
cout<<"RunTask"<<endl;
asyncIOService.post(bind(&JobClass::Run,aJob));
}

ThreadPoolClass::ThreadPoolClass(const ThreadPoolClass& orig) {
}

ThreadPoolClass::~ThreadPoolClass() {
cout<<"Kill ye all"<<endl;
asyncIOService.stop();
threadPool.join_all();
}

Класс работы

using namespace std;

class JobClass {
private:
int a;
int b;
int c;

public:

JobClass() {
//Empty Constructor
}

JobClass(int val) {
a = val;
b = val - 1;
c = val + 1;
}

void Run()
{
cout<<"a: "<<a<<endl;
cout<<"b: "<<b<<endl;
cout<<"c: "<<c<<endl;
}

};

Главный

using namespace std;

int main(int argc, char** argv) {

ThreadPoolClass ccThrPool(20);
ccThrPool.CreateThreadPool();
JobClass ccJob(10);
cout << "Starting..." << endl;
while(1)
{
ccThrPool.RunTask(&ccJob);
}
return 0;
}

Итак, в основном я создаю 20 потоков, но на данный момент я просто публикую только одну (одну и ту же) задачу для запуска ioservice (просто, чтобы упростить задачу и найти причину). Ниже приводится вывод, когда я запускаю эту программу в GDB:

Pushed
[New Thread 0xb7cd2b40 (LWP 15809)]
Pushed
[New Thread 0xb74d1b40 (LWP 15810)]
Pushed
[New Thread 0xb68ffb40 (LWP 15811)]
Pushed
[New Thread 0xb60feb40 (LWP 15812)]
Pushed
[New Thread 0xb56fdb40 (LWP 15813)]
Pushed
[New Thread 0xb4efcb40 (LWP 15814)]
Pushed
[New Thread 0xb44ffb40 (LWP 15815)]
Pushed
[New Thread 0xb3affb40 (LWP 15816)]
Pushed
[New Thread 0xb30ffb40 (LWP 15817)]
Pushed
[New Thread 0xb28feb40 (LWP 15818)]
Pushed
[New Thread 0xb20fdb40 (LWP 15819)]
Pushed
[New Thread 0xb18fcb40 (LWP 15820)]
Pushed
[New Thread 0xb10fbb40 (LWP 15821)]
Pushed
[New Thread 0xb08fab40 (LWP 15822)]
Pushed
[New Thread 0xb00f9b40 (LWP 15823)]
Pushed
[New Thread 0xaf8f8b40 (LWP 15824)]
Pushed
[New Thread 0xaf0f7b40 (LWP 15825)]
Pushed
[New Thread 0xae8f6b40 (LWP 15826)]
Pushed
[New Thread 0xae0f5b40 (LWP 15827)]
Pushed
[New Thread 0xad8f4b40 (LWP 15828)]
Starting...
RunTask
Kill ye all
[Thread 0xb4efcb40 (LWP 15814) exited]
[Thread 0xb30ffb40 (LWP 15817) exited]
[Thread 0xaf8f8b40 (LWP 15824) exited]
[Thread 0xae8f6b40 (LWP 15826) exited]
[Thread 0xae0f5b40 (LWP 15827) exited]
[Thread 0xaf0f7b40 (LWP 15825) exited]
[Thread 0xb56fdb40 (LWP 15813) exited]
[Thread 0xb18fcb40 (LWP 15820) exited]
[Thread 0xb10fbb40 (LWP 15821) exited]
[Thread 0xb20fdb40 (LWP 15819) exited]
[Thread 0xad8f4b40 (LWP 15828) exited]
[Thread 0xb3affb40 (LWP 15816) exited]
[Thread 0xb7cd2b40 (LWP 15809) exited]
[Thread 0xb60feb40 (LWP 15812) exited]
[Thread 0xb08fab40 (LWP 15822) exited]
[Thread 0xb68ffb40 (LWP 15811) exited]
[Thread 0xb74d1b40 (LWP 15810) exited]
[Thread 0xb28feb40 (LWP 15818) exited]
[Thread 0xb00f9b40 (LWP 15823) exited]
[Thread 0xb44ffb40 (LWP 15815) exited]
[Inferior 1 (process 15808) exited normally]

У меня есть два вопроса:

  1. Почему так, что мои темы выходят, даже когда я публикую
    задачи в цикле времени?
  2. Почему выходные данные из JobClass, т.е. значения переменных a, b
    и не может быть напечатан?

4

Решение

Я думаю, что это происходит потому, что вы создаете рабочий объект в методе CreateThreadPool, который автоматически уничтожается, когда выходит из области видимости -> в этом случае io_service не имеет активной работы и не обрабатывает ваши задачи.

Попробуйте сделать переменную экземпляра ‘work’ вашего класса ThreadPool, а не локальную в методе.

class ThreadPoolClass {
private:

thread_group threadPool;

asio::io_service asyncIOService;

std::auto_ptr<asio::io_service::work> work_;

public:
};ThreadPoolClass::ThreadPoolClass(int maxNumThreads) {
_Init();
maxThreads = maxNumThreads;
}

void ThreadPoolClass::CreateThreadPool() {

work_.reset(new asio::io_service::work(asyncIOService));

for (int i = 0; i < maxThreads; i++) {
cout<<"Pushed"<<endl;
threadPool.create_thread(bind(&asio::io_service::run, &asyncIOService));
}
}
3

Другие решения

Хорошо, я буду первым, кто признает, что не знаю boost, а точнее — boost :: asio из дыры в земле, но я знаю много о пулах потоков и рабочих бригадах.

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

На этом замечании, возможно ли, что деструктор вашего пула с точки входа main (), фактически, преждевременно убивает вашу рабочую команду? Я вижу join_all, но этот stop () дает мне воли. если он делает то, что подразумевает его название, это многое объясняет. Согласно описанию этого вызова stop () из документации:

Для завершения работы приложения необходимо вызвать
Функция-член stop () объекта io_service. Это приведет к
io_service run () вызов, чтобы вернуться как можно скорее, отказавшись
незавершенные операции и без разрешения готовых обработчиков
посланный.

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

Опять же, я не знаю boost: asio от Адама, но если бы я был на этом, я бы проверил конфигурацию запуска для объектов потока boost. Скорее всего, они требуют настройки того, как начать, как ждать и т. д. В сети должно быть множество примеров использования boost: asio, касающихся настройки того, что вы здесь описываете, а именно парадигмы рабочей группы. Я вижу boost :: asio TON на SO, так что, вероятно, также есть много связанных или близких вопросов.

Пожалуйста, не стесняйтесь понизить это, если это не является чем-то полезным, и я прошу прощения, если это так.

1