Russian Qt Forum
Апреля 24, 2025, 23:04 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

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

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: Многопоточная запись/чтение implicitly-shared классов  (Прочитано 9767 раз)
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.078 секунд. Запросов: 22.