Использование boost :: lock_guard для простой общей блокировки данных - PullRequest
14 голосов
/ 16 сентября 2010

Я новичок в библиотеке Boost и пытаюсь реализовать простые потоки производителей и потребителей, которые работают в общей очереди. Мой пример реализации выглядит так:

#include <iostream>
#include <deque>
#include <boost/thread.hpp>

boost::mutex mutex;
std::deque<std::string> queue;

void producer() 
{
    while (true) {
        boost::lock_guard<boost::mutex> lock(mutex);

        std::cout << "producer() pushing string onto queue" << std::endl;

        queue.push_back(std::string("test"));
    }
}

void consumer()
{
    while (true) {
        boost::lock_guard<boost::mutex> lock(mutex);

        if (!queue.empty()) {
            std::cout << "consumer() popped string " << queue.front() << " from queue" << std::endl;

            queue.pop_front();
        }
    }
}

int main()
{
    boost::thread producer_thread(producer);
    boost::thread consumer_thread(consumer);

    sleep(5);

    producer_thread.detach();
    consumer_thread.detach();

    return 0;
}

Этот код работает как я ожидаю, но когда main выходит, я получаю

/usr/include/boost/thread/pthread/mutex.hpp:45:    
    boost::mutex::~mutex(): Assertion `!pthread_mutex_destroy(&m)' failed.
consumer() popped string test from queue
Aborted

(Я не уверен, что вывод из consumer имеет отношение к этой позиции, но я оставил его.)

Я что-то не так делаю при использовании Boost?

Ответы [ 3 ]

11 голосов
/ 16 сентября 2010

Немного не по теме, но актуально imo (... ждет пламени в комментариях).

Модель потребителя здесь очень жадная, она постоянно проверяет наличие данных в очереди. Это будет более эффективно (тратит меньше циклов ЦП), если ваши потребительские потоки будут детерминированно пробуждены при наличии данных, используя межпотоковую сигнализацию, а не этот цикл блокировки и просмотра. Подумайте об этом следующим образом: хотя очередь пуста, это по сути замкнутый цикл, нарушенный только необходимостью получения блокировки. Не идеально?

void consumer()
{
    while (true) {
        boost::lock_guard<boost::mutex> lock(mutex);

        if (!queue.empty()) {
            std::cout << "consumer() popped string " << queue.front() << " from queue" << std::endl;

            queue.pop_front();
        }
    }
}

Я понимаю, что вы изучаете, но я бы не советовал использовать это в «реальном» коде. Для изучения библиотеки все же хорошо. К вашему сведению, это более сложный пример, чем необходимо, чтобы понять, как использовать lock_guard, поэтому вы стремитесь к высокой цели!

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

8 голосов
/ 16 сентября 2010

Вы даете своим потокам (производитель и потребитель) объект mutex, а затем отсоединяете их. Они должны бежать вечно. Затем вы выходите из своей программы, и объект mutex больше не действует. Тем не менее ваши потоки все еще пытаются использовать его, они не знают, что он больше не действителен. Если бы вы использовали определение NDEBUG, вы бы получили coredump.

Вы пытаетесь написать приложение демона, и в этом причина отключения потоков?

5 голосов
/ 16 сентября 2010

Когда выходит main, все глобальные объекты уничтожаются.Тем не менее, ваши темы продолжают работать.Поэтому у вас возникают проблемы, потому что потоки обращаются к удаленному объекту.

Суть в том, что вы должны завершить потоки перед выходом.Единственное, что нужно сделать, это заставить основную программу подождать (используя boost::thread::join), пока потоки не закончат свою работу.Возможно, вы захотите предоставить какой-то способ оповещения потоков о завершении работы, чтобы избежать слишком долгого ожидания.

Другая проблема заключается в том, что ваш потребительский поток продолжает работать, даже если нет данных.Возможно, вы захотите подождать на boost::condition_variable, пока не дадут сигнал о наличии новых данных.

...