F>Я почти ничего не смыслю в многопоточном программировании, поэтому прошу помощи у людей разбирающихся. F>Имеется вот такой код:
F>class ThreadPool;
F>struct ThreadData { F> ThreadPool *pool; F>}
F>unsigned __stdcall thread_run(void *args) { F> ThreadData *data = static_cast<ThreadData *> (args); F> Task *task = data->pool->getTask(); task->>invoke(); F>}
F>class ThreadPool { F>public: F> ThreadPool() {...}
F> void startAllThreads(int n) { F> ThreadData *data = new ThreadData; data->>pool = this; F> while (m_lThreads.size() != n) { F> hThread = (HANDLE)_beginthreadex( NULL, 0, &thread_run, (void *)data, 0, &threadID ); F> m_lThreads.push_back( hThread ); F> } F> }
F> Task *getTask() { F> Task *task = m_taskQueue->pop(); F> return task; F> }
F>}
F>int main() { F> ThreadPool pool; F> pool.startAllThreads(3); F> for(;) {} F>}
F>Код реализует механизм пула потоков. Содаётся Объект ThreadPool, который раздаёт задания созданным тредам.
F>Как я понимаю общий принцип работы такой: F>- создаётся процесс main() F>- он создаёт нужное количество тредов F>- main становится в бесконечный цикл
F>while (true) { F> — каждый тред запрашивает у ThreadPool задание F> — когда задание выполненно запрашивается следующее F>}
F>Но при этом непонятно: F>1) если main выполняет цикл for(;) {}, то как же он при этом отвечает на запросы тредов? я не могу понять как будет выглядеть общая картина взаимодействия потоков и процесса. F>2) Разве объект m_taskQueue при этом будет корректно отрабатывать запросы? Или нужно блочить очередь заданий через мьютексы или другие примитивы синхронизации? F>3) А как грамотно сделать блокировку потока в среде Win? F>4) При блокировке треда что с ним происходит? Ему системно выставляется какой то статус?
F>Есть некоторая специфика всего механизма пула потоков из-за которой приходится писать это самому, а не использовать какие то готовые решения (правда толковых я не нашёл, поэтому если у кого то есть что то подходящее с удовольствием изучу).
F>Заранее спасибо всем откликнувшимся!
1. В цикле внутри main лучше всего получать задания, например вызывать функцию ожидающую пользовательского ввода
и по результату создавать объект Tasк, который нужно поместь в очередь заданий. Не занятые работой потоки пула
должны ожидать появления заданчи в очереди. При появлении задачи один из потоков просыпаться вытаскивает ее из
очереди и начинает обработку. После завершения обработки, поток должен опять попытаться получить задачу из очереди,
а если очередь пуста заблокироваться на условной переменной.
2,3. Нужно использовать условные переменные например из boost.thread или ищите в API.
например c помощью boost.thread можно так:
class Task
{
public:
void execute();// выполнить задачу
};
Task* askUserForTask(); // получить задачу
class ThreadPool
{
public:
void startAllThreads(int n);
void queueTask(Task* new_task)
{
boost::unique_lock<boost::mutex> lock(mutex_);
task_queue_.push(new_task);
cond_.notify_one(); // разбудить один из потоков пула
}