Модераторы: Daevaorn
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> многопоточность: Продавец-Продавец 
:(
    Опции темы
cupper
Дата 14.2.2011, 15:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 525
Регистрация: 29.11.2006

Репутация: 1
Всего: 1



есть классическая задача для многопоточности Продавец-покупатель. Она много где описывается, но обычно не где не описывается решение для агресивной политики доступа, т.е. когда пауз между продай - купи нету, и каждый наровит впихнуть/взять как можно больше. 


У меня же задача, чуть более сложней. Когда два разных потока пытаются получить доступ к одному и томуже ресурсу притом один (1) чисто на запись, второй (2) на чтение и запись. ведущий поток это (1), так как если не будет данных  то (2) читать ничего не сможет. Это легко решается с помощью condition_variable.

А вот как организовать возможность разделение доступа к ресурсу между (1) и (2) я не могу понять. 

Должны корректно выполнятся следующие ситуации:
1) если (1) постоянно пишет в ресурс, то как только (2) попробует чтото прочитаться из ресурса (и не сможет этого сделать) то последушию запросы (1) временно блокируются что бы (2) смог получить доступ к ресурсу
2) если (2) постоянно читает/пишет в ресурс, то как только (1) попробует чтото записать в ресурса (и не сможет этого сделать) то последушию запросы (2) временно блокируются что бы (1) смог получить доступ к ресурсу

При этому (1) и (2) не должны покадить то место в котором они не смогли получить доступ, а должны доджаться когда они этот доступ получат.

Это примерно выглядет так
Код

template <typename T>
class SharedBuffer
{
    template<typename Y>
    friend std::ostream& operator<<(std::ostream& os, const SharedBuffer<Y>&);
public:
    SharedBuffer(void);
    ~SharedBuffer(void);
    // Добавляем в конец хранилища новые данные
    void push(std::list<T>&);
    // Возвращает копию первого элемента, и удаляет его из хранилища
    T pop();
private:
    std::list<T> _data;
    // блокировка на чтение/запись
    boost::mutex _mtx;
    // есть что прочитать !
    boost::condition_variable _cond;
};

template <typename T>
void SharedBuffer<T>::push(std::list<T>& buff)
{
    boost::lock_guard<boost::mutex> lock(this->_mtx);
    this->_data.insert(_data.end(), buff.begin(), buff.end());
    this->_cond.notify_one();
}

template <typename T>
T SharedBuffer<T>::pop()
{
    boost::unique_lock<boost::mutex> lock(this->_mtx);
    this->_cond.wait(lock, [this] {
        return !this->_data.empty();
    });

    T t;
    if(!this->_data.empty())
    {
        t = this->_data.front();
        this->_data.pop_front();
        return t;
    }
    // сюда ни когда не дойдект
    throw "Попытка получить данные из пустого хрпанилица";
    return T();
}



Этот работает для случая когда есть искуственная пауза между вызовами push->push и pop->pop
т.е. для случая
Код

поток 1:
while(1)
     x.push()

поток 2:
while(1)
    x.pop()


вероятность что pop() сможет влесть в работу потока1 крайне мала.
PM MAIL   Вверх
cupper
Дата 14.2.2011, 16:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 525
Регистрация: 29.11.2006

Репутация: 1
Всего: 1



придумал такую штуку
Код

template <typename T>
void SharedBuffer<T>::push(std::list<T>& buff)
{
    if(this->_giveMeRead)
        boost::this_thread::yield();
    boost::lock_guard<boost::mutex> lock(this->_mtx);
    //threadSleep(2);
    this->_data.insert(_data.end(), buff.begin(), buff.end());
    this->_cond.notify_one();
}

template <typename T>
T SharedBuffer<T>::pop()
{
    this->_giveMeRead = true;
    boost::unique_lock<boost::mutex> lock(this->_mtx);
    this->_cond.wait(lock, [this] {
        return !this->_data.empty();
    });
    this->_giveMeRead = false;
    //threadSleep(1);
    T t;
    if(!this->_data.empty())
    {
        t = this->_data.front();
        this->_data.pop_front();
        return t;
    }
    // сюда ни когда не дойдект
    throw "Попытка получить данные из пустого хрпанилица";
    return T();
}


При каждой попытке чтения (pop) мы пишем в буле переменную true свидетельствующую о том что нужно прочитать данные. Далее все как обычно пробуем залочить мютекс, и если не получается, то значит выполняется поток (1).
В этом самом потоке (1) вызывается операция push в которой первый делом проверяется, а нге было ли попыток ЧИТАТЬ, и если была (значение ture у переменной) то мы для текущего потока отдаем остаток времение yield().

Единственно что меня смущает так это что я не совсем понимаю как работает yield() и всегда ли будет поведение которое я описал выше ?
PM MAIL   Вверх
azesmcar
Дата 15.2.2011, 08:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 81
Всего: 211



Цитата(cupper @  14.2.2011,  15:41 Найти цитируемый пост)
вероятность что pop() сможет влесть в работу потока1 крайне мала. 

С чего это ей быть крайне малой? Назови причину, по которой у потока, вызывающего push вдруг появился приоритет. Они одинаково блокируют тут же mutex, почему именно у pop нет шансов?
После push()-а первый поток освобождает мьютекс, тем самым давая возможность второму потоку вызвать pop().

Цитата(cupper @  14.2.2011,  15:41 Найти цитируемый пост)
    // сюда ни когда не дойдект
    throw "Попытка получить данные из пустого хрпанилица";
    return T();

это зачем еще?


Это сообщение отредактировал(а) azesmcar - 15.2.2011, 08:35
PM   Вверх
cupper
Дата 15.2.2011, 10:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 525
Регистрация: 29.11.2006

Репутация: 1
Всего: 1



Цитата(azesmcar @ 15.2.2011,  08:34)
Цитата(cupper @  14.2.2011,  15:41 Найти цитируемый пост)
вероятность что pop() сможет влесть в работу потока1 крайне мала. 

С чего это ей быть крайне малой? Назови причину, по которой у потока, вызывающего push вдруг появился приоритет. Они одинаково блокируют тут же mutex, почему именно у pop нет шансов?
После push()-а первый поток освобождает мьютекс, тем самым давая возможность второму потоку вызвать pop()

т.е. даже при таком раскладе
Код

Поток1:
while(1)
    push()

Поток2
...
pop()
...


В потоке2 операция pop() особо долго не будет задерживаться из за того что в первом потоке постоянно занимается доступ ?


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

Цитата

это зачем еще?

это вылезло из за 
Код

if(!this->_data.empty())
    {

но вы правы, это излишне.
PM MAIL   Вверх
azesmcar
Дата 15.2.2011, 10:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 81
Всего: 211



Цитата(cupper @  15.2.2011,  10:21 Найти цитируемый пост)
В потоке2 операция pop() особо долго не будет задерживаться из за того что в первом потоке постоянно занимается доступ ?

cond.wait разблокирует мьютекс на время ожидания (пока не получит notification), в свою очередь push разблокирует его как только закончит свою работу. Т.е. на каждой итерации мьютекс освобождается, давая другому потоку возможность сделать свое дело. Любой, уважающий себя мьютекс должен дать поработать обоим потокам (смотри bounded waiting) smile 

Цитата(cupper @  15.2.2011,  10:21 Найти цитируемый пост)
Я видать попутал эту задачу с задачей писатель-много читателей, когда читатель действительно может не дождаться доступа к ресурсу из за того что к общей куче читателей постоянно могут прибавляться новые...

Там как раз пишущим потокам дается приоритет, так-как их мало.
вот тут я описывал.

Добавлено @ 10:30
Цитата(cupper @  15.2.2011,  10:21 Найти цитируемый пост)
это вылезло из за 


проверка
Цитата(cupper @  15.2.2011,  10:21 Найти цитируемый пост)
if(!this->_data.empty())

тоже лишняя.


Это сообщение отредактировал(а) azesmcar - 15.2.2011, 11:01
PM   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0740 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.