Поток современного доступа к переменным и механизмам синхронизации - PullRequest
1 голос
/ 02 сентября 2011

Я хочу понять, корректен ли следующий код

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

using namespace std;
using namespace boost;

class background_task
{
private:
    std::vector<int> numbers;

public:
    background_task()
    {
        i=0;
        numbers.assign(6000,0);
    }

    void someLongComputation()
    {
        while (++i<200)
        {
            //boost::mutex::scoped_lock(formutex);
            // cout << "Thread inside: i= " << this->i << endl;
            numbers.at(0)=i;
            cout << "Thread inside numbers= " << numbers.at(0) << endl; 
            boost::this_thread::sleep(boost::posix_time::milliseconds(100));
        }
    }

    std::vector<int>& getNumbers()
    {
        return numbers;
    }

    int i;
};

background_task f;

void valuePicker()
{
    int j=0;
    while ( (j++) < 20 )
    {
        boost::this_thread::sleep(boost::posix_time::milliseconds(1000));
        cerr << "First number= " << f.getNumbers().at(0) << endl;
    }
}

int main(void)
{
    boost::thread comp(boost::bind(&background_task::someLongComputation, &f));
    boost::thread value(valuePicker);

    comp.join();
    return 0;
}

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

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

Правильно ли передавать неконстантную ссылку или должно быть более безопасно, чтобы сделать ее константной?Созданные данные никогда не должны записываться, только читать ...

Спасибо!Я надеюсь с помощью этой ветки окончательно исправить мои сомнения начинающих в многопоточности ...

1 Ответ

0 голосов
/ 02 сентября 2011

Чтение и запись в общий массив numbers не является потокобезопасным. Искусственный sleep, который вы вставили, вероятно, маскирует проблему, если этот код действительно выполняется успешно.

Вы должны иметь надлежащую защиту от вектора numbers, что очень сложно, учитывая точный пример, потому что вы предоставляете этот вектор клиентам через публичную функцию getNumbers(). Это означает, что вы не можете контролировать, как клиенты background_task действительно взаимодействуют с данными.

Я бы добавил boost::mutex (как вы уже прокомментировали в функции длинных вычислений) и заблокировал его в функции длинных вычислений (только при доступе к массиву, чтобы сохранить небольшой объем блокировки). Я также удалил бы функцию getNumbers() и заменил бы ее функцией, чтобы получить значение из массива с определенным индексом, таким как int getNumberAt(size_t idx);, и также заблокировать boost::mutex.

...