Является ли потокобезопасная очередь хорошим подходом? - PullRequest
4 голосов
/ 30 августа 2011

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

void ProfilerCommunication::AddVisitPoint(ULONG uniqueId)
{
    CScopedLock<CMutex> lock(m_mutexResults);
    m_pVisitPoints->points[m_pVisitPoints->count].UniqueId = uniqueId;
    if (++m_pVisitPoints->count == VP_BUFFER_SIZE)
    {
        SendVisitPoints();
        m_pVisitPoints->count=0;
    } 
}

Приведенный выше кодиспользуется профайлером OpenCover (инструментом покрытия с открытым исходным кодом для .NET, написанным на C ++), когда вызывается каждая точка посещения.Мьютекс используется для защиты некоторой разделяемой памяти (блок 64 КБ, совместно используемый несколькими процессами 32/64 бит и C ++ / C #), когда он заполнен, он сигнализирует хост-процессу.Очевидно, что это довольно тяжело для каждой контрольно-измерительной точки, и я хотел бы сделать воздействие более легким.

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

Q.Есть ли потокобезопасная очередь в C ++ (Windows STL), которую я могу использовать - или очередь без блокировки, поскольку я не хотел бы заменять одну проблему другой?Считают ли люди мой подход разумным?


РЕДАКТИРОВАТЬ 1: Я только что нашел concurrent_queue.h в папке include - это может быть мой ответ ...?

Ответы [ 4 ]

1 голос
/ 30 августа 2011

Хорошо, я добавлю свой собственный ответ - concurrent_queue работает очень хорошо

, используя детали, описанные в этой статье MSDN Я реализовал параллельную очередь (и задачи, и мое первое лямбда-выражение C ++:)) Я не долго размышлял, потому что это спайк.

inline void AddVisitPoint(ULONG uniqueId) { m_queue.push(uniqueId); }

...
// somewhere else in code

m_tasks.run([this]
{
    ULONG id;
    while(true)
    {
         while (!m_queue.try_pop(id)) 
            Concurrency::Context::Yield();

        if (id==0) break; // 0 is an unused number so is used to close the thread/task
        CScopedLock<CMutex> lock(m_mutexResults);
        m_pVisitPoints->points[m_pVisitPoints->count].UniqueId = id;
        if (++m_pVisitPoints->count == VP_BUFFER_SIZE)
        {
            SendVisitPoints();
            m_pVisitPoints->count=0;
        }
    }
});

Результаты:

  • Приложение без контрольно-измерительных приборов = 9,3
  • Приложение со старымобработчик инструментов = 38,6
  • Приложение с новым обработчиком инструментов = 16,2
0 голосов
/ 30 августа 2011

Можно ли разгрузить общение клиента в отдельный поток? Тогда контрольные точки могут использовать локальное хранилище потока для записи своих попаданий, и им нужно только связаться с локальным потоком, чтобы выдать ссылку, когда она заполнена. Поток связи может затем потратить время на передачу данных фактическому сборщику, так как он больше не находится на горячей линии.

0 голосов
/ 30 августа 2011

Вы можете использовать очередь без блокировки.У Херба Саттера есть несколько статей здесь .

0 голосов
/ 30 августа 2011

Здесь упоминается, что не все операции с контейнерами являются поточно-ориентированными в Windows.Только ограниченное количество методов .И я не верю, что стандарты C ++ упоминают о поточно-безопасных контейнерах.Может я ошибаюсь, но проверил стандарты ничего не подошло

...