LINUX.ORG.RU

[c++] Многопоточность. Что можно? Как управлять одним потоком из другого?

 


0

1

Поток 1:

for(i = 0; i != 10000000; ++i) {
    ...
    if (m_need_some_stuff) {
        m_need_some_stuff = false;
        doSomeStuff();
    }
    ...
}

Поток 2:

...
if (!thread1->m_need_some_stuff) {
    thread1->m_need_some_stuff = true;
}
...
if (!thread1->m_need_some_stuff) {
    thread1->m_need_some_stuff = true;
}
...

Так можно? Или нет? Где вообще почитать что то, что можно, а что нельзя?

★★★★★

Не очень понял, что нужно. Похоже на продолжения/сопрограммы. Их в с++ нет, но можно сделать что-то похожее системой палок и веревок.

А еще посмотри man pthreads /cond, может поможет.

staseg ★★★★★
()
Ответ на: комментарий от staseg

Это кусок гипотетического кода из двух классов. Объекты этих классов в разных потоках. Второй управляет первым.

Obey-Kun ★★★★★
() автор топика

> Где вообще почитать что то, что можно, а что нельзя?

JCIP. Там до чертиков низкоуровневой инфы, несмотря на название. Написано ну очень просто и доступно.

anonymous
()

> Где вообще почитать

google://pthreads

LamerOk ★★★★★
()

Может сделать взаимодействие через пайп. Один поток засыпает на чтении данных из пайпа. Пришли данные (пускай это будет 1 байт с командой), поток очнулся, сделал работу и снова заснул на чтении.

Второй поток собственно пишет команды в пайп.

pathfinder ★★★★
()
Ответ на: комментарий от Obey-Kun

Скажем, первое в run() у QThread, а второе в главном окне.

Блин, ну дык стандартный механизм Qt SLOT/SIGNAL. Если слот и сигнал в разных потоках, то вместо прямого вызова идет проброс через очередь сообщений.

pathfinder ★★★★
()

Это случайно не что-то вроде очереди задач? Если она, то все кардинально неверно.

Vamp
()

По-научному это называется busywait. Так делают обычно, если ожидание одним потоком будет не долгим (< 1ms). Тогда накладные расходы на семафоры/cond_valiable/etc будет больше. А если ждать долго - то надо мутексами (или любым другим подходящим блокирующим примитивом, в данном случае я бы использовал cond_variable).

nanoo_linux
()
Ответ на: комментарий от Obey-Kun

я в своём qthread не хочу включать event lopp.

Из религиозных соображений?

pathfinder ★★★★
()

Через шаблон observer.

anonymous
()

Так можно, но осторожно.

Пример граблей:

Поток 2 хочет данных и выставляет needSomeStuff.

Поток 1 замечает это, сбрасывает needSomeStuff и начинает делать этот самый stuff.

Поток 2 всё ещё хочет данных (которые поток 1 ещё ему не дал), видит, что needSomeStuff cброшен и устанавливает его.

Поток 1 доделывает stuff.

Поток 1 видит, что needSomeStuff установлен и начинает делать stuff по новой, в результате чего а) делает лишнюю работу, б) делает работу некорректно (так как предполагает, что она ещё не сделана), в) делает работу корректно, но иначе, в результате чего результаты первого и второго вариантов смешиваются, образуя кашу, г) вообще падает по тем же причинам, что и в пункте б. Нужное подчеркнуть.

Miguel ★★★★★
()
Ответ на: комментарий от Miguel

Понятно. Ну конкретно в моей программе такое невозможно, ибо needSomeStuff поток 2 выставляет лишь после того, как получил Stuff.

Тогда другой вопрос. А если у нас вместо m_need_some_stuff есть какой-нибудь сложный объект, то так уже прокатит? Может ли случиться так, что во время проверки в первом потоке, второй его изменит и всё упадёт?

А если ждать долго - то надо мутексами

Почему? В данном случае needSomeStuff дергается раз 150-2000 мс.

Obey-Kun ★★★★★
() автор топика
Ответ на: комментарий от Obey-Kun

Поток 1:

for(i = 0; i != 10000000; ++i) {
    ...
    if (m_need_some_stuff) {
        m_need_some_stuff = false;
        doSomeStuff();
        emit hereIsYourStuff(m_stuff);
    }
    ...
}
Поток 2:

void getStuff(Foo stuff) // слот
{
    someLongOperation(stuff); // обработаем stuff, на это уйдёт как минимум 150 мс (гарантированно таймером)
    thread1->needMoreStuff() ; // устанавливает m_need_some_stuff в true
}
Obey-Kun ★★★★★
() автор топика
Ответ на: комментарий от Yareg

> Без блокировок менять использовать одни данные в разных тредах? Нельзя.

можно, но со смыслом ;) неблокирующие операции быстрее, профит

stevejobs ★★★★☆
()
Ответ на: комментарий от Obey-Kun

Тогда другой вопрос. А если у нас вместо m_need_some_stuff есть какой-нибудь сложный объект, то так уже прокатит? Может ли случиться так, что во время проверки в первом потоке, второй его изменит и всё упадёт?

Естествеено, может. Если сложный объект - надо закрывать его мьютексом.

А вообще да, выглядит малость противоестественно. Не знаю, как в Qt, в boost::asio, например, можно делать io_service.post(...), и какой-то тред из пула будет асинхронно выполнять задание. В принципе такое и руками сделать просто.

ratatosk
()
Ответ на: комментарий от Yareg

> Без блокировок менять использовать одни данные в разных тредах? Нельзя.

Можно, если делать это атомарно.

Кроме того, есть всякие интересные lockless алгоритмы типа RCU.

Relan ★★★★★
()
Ответ на: комментарий от ratatosk

(дурацкий вопрос) а почему bool можно так менять, а сложный объект нельзя?

Obey-Kun ★★★★★
() автор топика
Ответ на: комментарий от Yareg

Блин. А как они могут проявиться, эти проблемы? Сегфолт при одновременном считывании и записи из разных потоков?

Obey-Kun ★★★★★
() автор топика
Ответ на: комментарий от Obey-Kun

Это процессор делает вид, что оно делается моментально. В x86 единственная команда, которая гарантирует, что всё прошло целиком - lock xchg, мьютексы именно ей и ставятся, но она очищает конвейр, и блокирует все другие ядра, что может привести к тормозам при слишком частом употреблении ( http://ru.wikipedia.org/wiki/Spinlock ).

А сегфолта не будет, просто программа может работать неправильно.

Yareg ★★★
()

Может погуглить producer-consumer и потом модифицировать?

vertexua ★★★★★
()
Ответ на: комментарий от Obey-Kun

Что-то именно чтобы с bool, который занимает 1 байт, может принимать значение только 0 и 1 и который мы в каждом потоке либо только читаем, либо только пишем, не могу придумать... Может быть, ничего и не может даже теоретически произойти.

Yareg ★★★
()
Ответ на: комментарий от Yareg

> В x86 единственная команда, которая гарантирует, что всё прошло целиком - lock xchg

Неправда. См. Intel Software Developer’s Manual, Volume 3A, раздел 8.1.1 Guaranteed Atomic Operations, а также 8.1.2.2 Software Controlled Bus Locking.

Relan ★★★★★
()
Ответ на: комментарий от Relan

Лучше читать по мануалу, действительно, но вроде на х86 запись/чтение машинных слов атомарны, то есть, если чтение совпадает с записью, то ты можешь прочитать либо новое, либо старое значение, фарш не прочитаешь.

ratatosk
()
Ответ на: комментарий от ratatosk

> Лучше читать по мануалу, действительно, но вроде на х86 запись/чтение машинных слов атомарны, то есть, если чтение совпадает с записью, то ты можешь прочитать либо новое, либо старое значение, фарш не прочитаешь.

Да, действительно, лучше читать мануал. :) Там есть важное условие — чтение/запись будет атомарна только если ячейка памяти не пересекает границу кэшлайна.

Relan ★★★★★
()
Ответ на: комментарий от Obey-Kun

Бул границу кеш-лайна точно не пересечет. Если это один байт.

ratatosk
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.