Ищем оптимальную многопоточную очередь сообщений - PullRequest
1 голос
/ 28 июля 2010

Я хочу запустить несколько потоков внутри процесса.Я ищу наиболее эффективный способ передачи сообщений между потоками.

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

Сообщения будут иметь приоритет.Я хочу сам управлять этим процессом.

Без дорогостоящей блокировки или синхронизации, какой лучший способ сделать это?Или для этого уже есть хорошо зарекомендовавшая себя библиотека?(Delphi, C или C # в порядке).

Ответы [ 2 ]

2 голосов
/ 28 июля 2010

Трудно понять, не повторяя много ошибок, которые другие люди уже сделали для вас:)

Взгляните на Intel Threading Building Blocks - в библиотеке есть несколько хорошоразработанные шаблоны очередей (и другие коллекции), которые вы можете протестировать и увидеть, которые лучше всего соответствуют вашим целям.

1 голос
/ 28 июля 2010

Если вы собираетесь работать с несколькими потоками, трудно избежать синхронизации.К счастью, это не очень сложно.

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

#include <Windows.h>

class CTkCritSec
{
public:
    CTkCritSec(void)
    {
        ::InitializeCriticalSection(&m_critSec);
    }
    ~CTkCritSec(void)
    {
        ::DeleteCriticalSection(&m_critSec);
    }
    void Lock()
    {
        ::EnterCriticalSection(&m_critSec);
    }
    void Unlock()
    {
        ::LeaveCriticalSection(&m_critSec);
    }

private:
    CRITICAL_SECTION m_critSec;
};

Вы можете сделать это еще проще с помощью класса «autolock», который вы блокируете / разблокируете.

class CTkAutoLock
{
public:
    CTkAutoLock(CTkCritSec &lock)
    : m_lock(lock)
    {
        m_lock.Lock();
    }
    virtual ~CTkAutoLock()
    {
        m_lock.Unlock();
    }
private:
    CTkCritSec &m_lock;
};

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

Теперь вы можете сделать простую очередь сообщений из очереди с приоритетами std

#include <queue>
#include <deque>
#include <functional>
#include <string>

struct CMsg
{
    CMsg(const std::string &s, int n=1)
    : sText(s), nPriority(n) 
    {
    }
    int         nPriority;
    std::string sText;

    struct Compare : public std::binary_function<bool, const CMsg *, const CMsg *>
    {
        bool operator () (const CMsg *p0, const CMsg *p1)
        { 
            return p0->nPriority < p1->nPriority; 
        }
    };
};

class CMsgQueue : 
         private std::priority_queue<CMsg *, std::deque<CMsg *>, CMsg::Compare >
{
public:
    void Push(CMsg *pJob)
    {
        CTkAutoLock lk(m_critSec);
        push(pJob);
    }
    CMsg *Pop()
    {
        CTkAutoLock lk(m_critSec);

        CMsg *pJob(NULL);
        if (!Empty())
        {
            pJob = top();
            pop();
        }
        return pJob;
    }
    bool Empty()
    {
        CTkAutoLock lk(m_critSec);

        return empty();
    }

private:
    CTkCritSec m_critSec;
};

СодержимоеCMsg может быть чем угодно.Обратите внимание, что CMsgQue наследует конфиденциально от std :: priority_queue.Это предотвращает необработанный доступ к очереди без использования наших (синхронизированных) методов.

Назначьте подобную очередь каждому потоку, и вы уже в пути.

Отказ от ответственности Код здесь был быстро соединен, чтобы проиллюстрировать точку.Вероятно, он содержит ошибки и требует проверки и тестирования перед использованием в производстве.

...