Это, как я это реализовать.
Во-первых, у меня есть базовый класс ThreadWorker, из которого могут произойти мои фактические задачи обработки. Обратите внимание, что это Windows, специфична, но вы можете заменить повысить семафор для CriticalSection, а реализация POSIX семафоров здесь: http://linux.die.net/man/7/sem_overview
class ThreadWorker
{
public:
ThreadWorker(void)
{
signalfinished = NULL;
forcesignal = false;
}
virtual ~ThreadWorker(void)
{
if (signalfinished!=NULL) ReleaseSemaphore(signalfinished,1,NULL);
}
DWORD ThreadId;
HANDLE threadhandle;
HANDLE signalfinished;
bool forcesignal;
static DWORD WINAPI workerthread(void *param)
{
ThreadWorker *worker = (ThreadWorker*)param;
worker->signalfinished = CreateSemaphore(NULL,0,1,NULL);
worker->RunTask();
ReleaseSemaphore(worker->signalfinished,1,NULL);
}
void StartWorker()
{
CreateThread(NULL,NULL,ThreadWorker::workerthread,this,0,&ThreadId);
}
void WaitUntilWorkerFinished()
{
DWORD waitresult;
do
{
waitresult = WaitForSingleObject(signalfinished,1000);
} while (waitresult!=WAIT_OBJECT_0 && !forcesignal);
}
virtual void RunTask()=0;
};
Тогда у меня есть ThreadManager, который управляет очередью объектов ThreadWorker. Опять же, вы можете заменить мьютекс для CriticalSection. Я предпочитаю std :: list для std :: vector, потому что вектор смежный.
class ThreadManager
{
CRITICAL_SECTION critsec;
std::list<ThreadWorker*> taskqueue;
public:
ThreadManager(void)
{
InitializeCriticalSection(&critsec);
}
void AddTaskToQueue(ThreadWorker *task)
{
EnterCriticalSection(&critsec);
taskqueue.push_back(task);
LeaveCriticalSection(&critsec);
}
void ProcessTaskQueue()
{
while (true)
{
EnterCriticalSection(&critsec);
ThreadWorker *thistask = taskqueue.front();
taskqueue.pop_front();
LeaveCriticalSection(&critsec);
thistask->StartWorker();
}
}
~ThreadManager(void)
{
DeleteCriticalSection(&critsec);
}
};
Чтобы добавить задачу в очередь, нам нужен подкласс, который реализует ThreadWorker.
class SomeWorkerTask : public ThreadWorker
{
public:
SomeWorkerTask(void);
virtual ~SomeWorkerTask(void);
void RunTask()
{
std::cout << "Hello, I am a worker task runing on thread id " << ThreadId << std::endl;
}
};
Создать новый экземпляр SomeWorkerTask и добавить его в очередь, а затем обрабатывать очереди. В вашем случае у вас будут разные потоки, добавляющие задачи в очередь и обработка очереди, но я предполагаю, что вы получите эту идею.
SomeWorkerTask *atask = new SomeWorkerTask();
ThreadManager manager;
manager.AddTaskToQueue(atask);
manager.ProcessTaskQueue();
Если вы хотите знать, когда задача завершения обработки, вы можете вызвать ThreadWorker :: WaitUntilWorkerFinished из другого потока или добавить вызов ProcessTaskQueue. Вы можете изменить ThreadManager, чтобы у вас была очередь ожидающих задач, одна очередь запущенных задач и третья очередь готовых задач. После того, как вы вытащите задание из очереди ожидания, вы добавите ее в рабочую очередь и с помощью семафора задачи определите, когда она была завершена, затем добавьте ее в готовые задачи/удалите ее из запущенных задач. Обратите внимание, что стандартные контейнеры, такие как вектор, карта и список, не являются потокобезопасными, поэтому вы всегда должны окружать операции, которые вставляют/удаляют из контейнера с блокировкой взаимного исключения, например критический раздел или мьютекс.
Надеюсь, что это поможет.
Не прямой ответ на Ваш вопрос, но вы должны определенно взглянуть на повышение :: Asio (http://www.boost.org/doc/libs/ 1_55_0/doc/html/boost_asio.html), особенно если вы работаете на веб-сервере. Он позволяет разделить работу на разные потоки (см., Например, http://stackoverflow.com/q/14265676/991425) и ist специально для сетевого ввода-вывода, который вы планируете делать много, при программировании веб-сервера , Я полагаю. – Haatschii
Вам понадобится мьютекс для очереди. При использовании окон самым простым является CriticalSection. В Unix, мьютекс. Чтобы поток сигнализировал, когда он закончен, я использую семафор и ждут его. –
Спасибо за ваши комментарии! – mitch