Идентифицировать объекты в boost :: shared_ptr ‹boost :: thread›

Я создаю приложение на основе примера на сайте boost. Вот соответствующие определения, о которых следует знать:

typedef boost::shared_ptr< connection > connection_ptr;
std::set< connection_ptr> connections_;
std::vector< boost::shared_ptr< boost::thread> > threads;

где соединение - это класс.

В одном из файлов connection_manager .cpp, они делают так:

void connection_manager::start(connection_ptr c)
{
  connections_.insert(c);
  c->start();
}

Теперь я хочу запускать каждое новое соединение в отдельном потоке из-за структуры моей программы. Итак, я изменил приведенное выше в соответствии с:

void connection_manager::start(connection_ptr c)
{
    boost::shared_ptr< boost::thread > thread(new boost::thread(
                        boost::bind(&connection::start, c)));

    // push the newely created thread into the vector
    threads.push_back(thread);

    // save the connection in our set
    connections_.insert(c);
}

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

void connection_manager::stop(connection_ptr c)
{
    connections_.erase(c);
    c->stop();

    // find the connection in among the threads and join that thread
}

Но, как следует из комментария выше, как мне найти c среди всех потоков и остановить только этот поток. Я хочу вызвать функцию join () для этого потока.


Обновление:

Думаю, это то, что я действительно хочу иметь! Поэтому я объявляю свою переменную как

std::map < connection_ptr, boost::shared_ptr < boost::thread > > threads;

Но тогда как мне создать новый протектор так же, как и раньше? Нравится:

boost::shared_ptr < boost::thread > thread(new boost::thread(
                        boost::bind(&connection::start, c)));

Но что тогда будет следующим шагом? Извините, что запуталась ... :-)


person Thomas Johansson    schedule 13.05.2011    source источник


Ответы (2)


Если вы используете карту (или другой ассоциативный контейнер) вместо вектора, вы можете поддерживать связь между соединениями и потоками:

std::map<connection_ptr, boost::shared_ptr<boost::thread> > threads;

позволяет писать:

threads[connection] = thread;

вместо вызова push_back после создания потока, а затем:

threads[connection]->stop();

позже, когда вы захотите его найти.

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

person Flexo    schedule 13.05.2011
comment
Просто чтобы я понял, что вы правильно: если карта является вашей целью, это что-то довольно уязвимое? Как я могу это сделать? - person Thomas Johansson; 14.05.2011
comment
Проблема в том, что кому-то злу очень легко написать программу, которая подключается к вашему приложению 100 раз в секунду. Создание потоков довольно дорого с точки зрения ОЗУ и процессорного времени, необходимого для каждого потока. Если каждое из этих соединений создает новый поток (а затем, возможно, связывает его дальше), производительность системы постепенно снижается. Обычное решение - использовать пул потоков для создания некоторого фиксированного числа потоков, а затем делить каждый поток между несколькими подключениями. - person Flexo; 14.05.2011
comment
Я пытаюсь в этом разобраться, спасибо за помощь. Поделитесь каждым потоком между несколькими подключениями, как вы говорите, означает ли это что-то вроде Пример HTTP-сервера 2. Io_services создаются в разных потоках. Затем новые соединения используют одно из них. Это то, что вы имеете в виду? Что означает для потока программы наличие служб io в разных потоках? Что же тогда (например, обратный вызов async_read ()) будет выполняться в разных потоках? - person Thomas Johansson; 15.05.2011
comment
Это похоже на то, что я предлагал. (Я подумал, что с помощью ASIO есть способ сделать это лучше, но точно не могу вспомнить). В основном происходит то, что происходит при небольшом количестве соединений, равном размеру пула ›количеству соединений, поэтому вы фактически получаете соотношение соединение: поток 1: 1. По мере увеличения количества подключений вы начинаете обслуживать несколько подключений одним потоком, но производительность этого процесса имеет тенденцию более изящно ухудшаться под нагрузкой. - person Flexo; 15.05.2011
comment
Хорошо, я понял, спасибо! Но что бы вы посоветовали мне сделать, чтобы добиться лучших результатов? Я новичок в этой теме производительности / потока, поэтому есть ли что-нибудь, что я мог бы изменить в примере HTTP Server 2, чтобы повысить производительность? - person Thomas Johansson; 15.05.2011
comment
В примере HTTP-сервера 2 производительность, вероятно, будет хорошей, если а) для обслуживания запросов используется правильное количество потоков, чтобы увидеть результаты тестов при реалистичных рабочих нагрузках и б) если все запросы относительно равны. Если у вас есть несколько тривиальных запросов, а некоторые более сложные, возможно, что циклический выбор не будет оптимальным. - person Flexo; 15.05.2011
comment
Спасибо! В моем случае, думаю, это будет хорошее решение. Еще один вопрос: то, что io_services выполняются в разных потоках, означает ли это, что соединения, использующие их, будут работать в другом потоке? То есть соединение будет работать в том же потоке, что и его io_service? - person Thomas Johansson; 16.05.2011
comment
@ThomasJohansson Да, асинхронные обратные вызовы выполняются в том же потоке, что и io_service. (Вы также можете обрабатывать один объект io_service несколькими потоками, см. boost.org/doc/libs/1_48_0/doc/html/boost_asio/tutorial/) (PS вы должны как добавить голос за ответ awoodland, так и принять один из полученных ответов !) - person Darren Cook; 13.02.2012

Если ваше соединение всегда привязано к потоку, имеет смысл просто указать объекту соединения на поток, в котором он работает, и переместить логику запуска в потоке в сам класс соединения.

person Jan Hudec    schedule 13.05.2011