Russian Qt Forum
Ноябрь 02, 2024, 10:29 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: Многопоточная запись/чтение implicitly-shared классов  (Прочитано 9469 раз)
Akon
Гость
« : Октябрь 30, 2011, 11:33 »

Часто приходится видеть такое:
Код:
QByteArray a("some data");

// write access, thread #1
void funcFromThread1()
{
a = QByteArray();  // before assignment assume ref. count == 1
...
}

// read-only access, thread #2
void funcFromThread2()
{
const QByteArray b = a;  // potential access to released memory (pointed by a.d)
...
}

В документации сказано о безопасности счетчика ссылок и о небезопасности расшаренных данных. Вероятно, у многих (в т.ч. и у меня) создается впечатление, что shallow copy
Код:
const QByteArray b = a;
безопасно в многопоточной среде, но при одновременном чтении/записи, как приведено выше, это не так.

Безопасный доступ: сериализация (мьютексы) и lock-free вариант, приведенный ниже:
Код:
// lock-free

QByteArray a("some data");

// write access, thread #1
void funcFromThread1()
{
const QByteArray tmp = a;  // ref.count >= 2 while writing a
a = QByteArray();
...
}

// read-only access, thread #2
void funcFromThread2()
{
const QByteArray b = a;  // safe access while writing a
...
}

имхо, как-то стоило бы отразить эту проблему в документации, например, в boost подобное использование разжевано для boost::shared_ptr.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #1 : Октябрь 30, 2011, 14:01 »

Ну Вы бы уж "разжевали" для широкого круга читателей напр
Код
C++ (Qt)
QByteArray &QByteArray::operator=(const QByteArray & other)
{
   other.d->ref.ref();
   if (!d->ref.deref())
       qFree(d);
   d = other.d;
   return *this;
}
 
Читающая нитка может вклиниться перед qFree и рухнуть. Чтобы исключить такое дело надо запастись счетчиком ссылок >= 2. Добавим что читающий может получить как новые так и старые данные - как получится
Записан
Akon
Гость
« Ответ #2 : Октябрь 30, 2011, 19:43 »

Да, спасибо за дополнение-"разжевку".
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #3 : Октябрь 30, 2011, 20:03 »

Igors
присваивание шаред данных атомарно. никто никуда вклинится не может.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #4 : Октябрь 30, 2011, 20:58 »

присваивание шаред данных атомарно. никто никуда вклинится не может.
Уголовники показывают костяшку домино 5/6 и говорят "выбирай". Что выберет умный человек?  Улыбающийся Вот также и читающая нитка 
Записан
andrew.k
Гость
« Ответ #5 : Октябрь 30, 2011, 21:02 »

Поясни про уголовников?)
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #6 : Октябрь 30, 2011, 21:08 »

Код
C++ (Qt)
   if (!d->ref.deref())
                                  <-- пробой здесь
       qFree(d);
 
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #7 : Октябрь 30, 2011, 21:11 »

2 нитки _не могут_ владеть 1й копией. у каждой нитки свой d.
Записан
Akon
Гость
« Ответ #8 : Октябрь 30, 2011, 21:50 »

Это так, до поры
Код:
d = other.d;

Про уголовников тоже интересно.
Записан
andrew.k
Гость
« Ответ #9 : Октябрь 30, 2011, 21:52 »

2 нитки _не могут_ владеть 1й копией. у каждой нитки свой d.
А почему? В том смысле, где это написано?

Qt uses an optimization called implicit sharing for many of its value class, notably QImage and QString. Beginning with Qt 4, implicit shared classes can safely be copied across threads, like any other value classes. They are fully reentrant. The implicit sharing is really implicit.
Threads and Implicitly Shared Classes
Какой из этого вывод?
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #10 : Октябрь 30, 2011, 22:04 »


andrew.k
не, это я туплю просто.
Записан
Akon
Гость
« Ответ #11 : Октябрь 30, 2011, 22:10 »

Ну там дальше написано
Цитировать
...  Atomic reference counting does, however, guarantee that a thread working on its own, local instance of an implicitly shared class is safe. ...
Но проблема возникает как раз при переустановке своего d.

Авварон
у вас создалось впечатление  Улыбающийся
Записан
andrew.k
Гость
« Ответ #12 : Октябрь 30, 2011, 22:10 »

Тогда, что получается по теме? я не очень понимаю.
Нужно использовать мютексы при доступе к QByteArray? Потому что без них ерунда какая-то получается.
Мыль ТС я не очень понял. Точнее приведенный там код.
Записан
andrew.k
Гость
« Ответ #13 : Октябрь 30, 2011, 22:12 »

Ну там дальше написано
Цитировать
...  Atomic reference counting does, however, guarantee that a thread working on its own, local instance of an implicitly shared class is safe. ...
Но проблема возникает как раз при переустановке своего d.

Получается другой поток в принципе не увидит изменений сделанных другим потоком.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #14 : Октябрь 31, 2011, 09:55 »

Код
C++ (Qt)
QByteArray &QByteArray::operator=(const QByteArray & other)
{
   other.d->ref.ref();
   if (!d->ref.deref())
       qFree(d);
   d = other.d;
   return *this;
}
 
Допустим d->ref.defref() вернул false и в этот момент ОС передал управление др. нитке. Конечно d = other.d выполнится атомарно, но это будет потом, когда текущая нитка снова получит управление. А сейчас в читающей нитке это d пройдет как член other, ну читатель увеличит счетчик ref и присвоит указатель d своему. Может даже успеет что-то сделать пока проснувшаяся нитка не выполнит qFree  Улыбающийся
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.165 секунд. Запросов: 23.