LINUX.ORG.RU

А как в других ЯП разруливают блокирующие функции?

 


0

2

Возможно спрошу криворуко, звыняйте.

Вот есть две функции-примера, неважно на каком ЯП:

function first() {
  printf("Out 1\n");
  sleep(1);
}

function second() {
  printf("Out 2\n");
  sleep(3);
}

function main() {
 while(true) {
  first(); // Эта функция не выполнится пока second() не завершится
  second(); // Эта функция не выполнится пока first() не завершится
 }
}

Каким обычно способом решается вопрос блокировок в коде?

★★★★★
Ответ на: комментарий от hippi90

Я так понимаю это просто отдельный экземпляр текущего кода с сохранением всего состояния, но без доступа к общему пространству?

Т.е. если я условно говоря заведу глобальную переменную, и в функции «first()» присвою ей значение, то в функции «second()» я ее уже не прочитаю?

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

Потоки обладают общим пространством памяти. Глобальные переменные можно читать и писать из разных потоков, естественно с учетом синхронизации, какой-нибудь RwLock, например. Но вообще глобальные переменные и потоки - это антипаттерн.

hippi90 ★★★★★
()

в нормальном софте слипов не бывает. имеет смысл только в маинлупах однопотоковых поделок на микроконтроллерах. причем простейщих, навроде контроллера температуры в курятнике.

в серьезном коде слип - это 100 проц. недостаток квалификации погромиста. короче - увидел слип - бей лопатой по смотровым отверстиям автора!

должна быть событийно-ориентированная парадигма или типа «event-driven» paradigm, где потоки не спят на таймере, а спят на ожидании ивентов(событий). так работает весь ответственный софт.

изучай это, будешь настоящим

https://ru.wikipedia.org/wiki/%D0%A1%D0%BE%D0%B1%D1%8B%D1%82%D0%B8%D0%B9%D0%BD%D0%BE-%D0%BE%D1%80%D0%B8%D0%B5%D0%BD%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%BD%D0%BE%D0%B5_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5

alysnix ★★★
()

Вообще, не зная масштаба задачи, сложно предложить что-то конкретное.

1. Для твоего примера, когда два каких-то действия надо просто постоянно запускать в параллель - я бы взял тупо два потока + какой-то простой mutex, если нужна снхронизация.

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

3. Задач много и они разные - смотрел бы уже в сторону модели акторов.

hippi90 ★★★★★
()

А как в других ЯП разруливают блокирующие функции?

Единого, общего для всех ситуаций решения нет. Смотришь что вызывает дедлок и переделываешь синхронизацию.

kaldeon
()
Последнее исправление: kaldeon (всего исправлений: 1)
Ответ на: комментарий от kaldeon

Единого, общего для всех ситуаций решения нет. Смотришь что вызывает дедлок и переделываешь.

Не везде это возможно. Если например какой-нибудь fread или как его там читает гиговый файл (нужно это или нет - вопрос другой) - как это переделать, если файл все равно нужно считать.

windows10 ★★★★★
() автор топика

за слип надо голову отрубать преподавателям и учебным пособиям.

на слипе можно написать только безответственную, низкой временной точности пикалку, и больше он не пригоден ни на что серьезное.

при слипе тред уходит с шедулера и встает в очередь таймера, и тот его возобновит через нужное количество микросекунд. и усьо.

по сути тред тормозят на N микросекунд, с целью - лишь бы заткнулся и не жрал процессорные такты.

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

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

В сабже нет вопросов по sleep, там есть про выполнение кода. Поменяй на fread гигового файла - будет тот же эффект. Да да, fread не нужен.

windows10 ★★★★★
() автор топика
Последнее исправление: windows10 (всего исправлений: 1)
Ответ на: комментарий от windows10

Это стандартная функция, или какая-то библиотека ?

есть понятие треда. с тредом можно делать некие стандартные действия. создавать, стартовать, паузить, возобновлять, убивать. в разных языках и либах могут быть разные названия всему этому, но смысл всегда одинаков. это стандартный набор функций для работы с тредами

alysnix ★★★
()

Блокировки это свойство ядра, а не языков. Полагаю, ответ на основной вопрос - никак. Или что значило разруливать? Ну какие-то две длинные функции с IO выполняются друг за другом, что здесь не так?

В некоторых языках есть асинк, который позволяет реализовать движок, использующий этот самый асинк языка, который опять же полагается на возможности ядра. В некоторых языках этот движок встроен как рантайм по умолчанию и от него нельзя отказаться (js, golang, lua).

neumond
()

Каким обычно способом решается вопрос блокировок в коде?

я обычно убираю эти sleep - от этого и код становится быстрее !

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

Есть то оно есть, а если нет, то можно сделать. Только ни пыховский ни питонячий код не thread safe. В рантайме этих языков переменные это структуры и если обращаться к ним из разных потоков будет биг бадабум

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

Угомонись. У тебя в линуксе ядро процессора что делает когда ему делать нечего? Вызывает инструкцию halt, то есть спит.

это не тот слип вообще, уася. даже близко к семантике слипа треда тут нет. слипы и хальты процов - это отключка блоков и/или полное прекращения исполнения команд до возникновения внешнего прерывания. главный тут тезис - ничего не делаем, пока не вознкнет внешний сигнал. чиcтый event-driven, а не - «спим 10 мс».

короче ты явно не в теме.

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 2)
Ответ на: комментарий от windows10

В сабже нет вопросов по sleep, там есть про выполнение кода. Поменяй на fread гигового файла - будет тот же эффект. Да да, fread не нужен.

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

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

Блокировки это свойство ядра, а не языков. Полагаю, ответ на основной вопрос - никак. Или что значило разруливать? Ну какие-то две длинные функции с IO выполняются друг за другом, что здесь не так?

Не обязательно. Думаю лучше напишу сразу мой юзкейс об который я столкнулся. Это индикатор состояния в ФМ.

Вот выделил я файлы\директории для копирования. Соответственно перед копированием мне сперва нужно сформировать полный рекурсивный список. Низкоуровнево это делается упрощенно говоря комбинацией cd и ls.

Задача: выводить в окно, название каждой сканируемой директории. Для этого в середине этого рекурсивного цикла вызывается GTK-шная функция, если точнее gtk_label_new, которая выводит название директории в виджет.

Не знаю почему, но эта функция срабатывает только после отработки всей функции, т.е. по завершению цикла перебора вложенных субдиректорий. Ну и соответственно выводит только название последней директории.

Это - языконезависимо. Написал пример на PHP, на C и на Питоне - везде ведет себя одинаково. Ясен хер что это косяк GTK, потому что тот же самый echo \ printf отрабатывает нормально и выводит все что нужно.

Задумка была повесить функцию вывода значения переменной (пусть это будет *char) на таймер, а с функции перебора файлов просто изменять значение переменной. Но GTK шный таймер оказывается тоже блокируется.

Вот я и решил все же полезть в threads.

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

Кооперативную многозадачность в одном потоке

еще одна жертва await’ов.

кооперативная многозадачность, это натуральное переключение контекста, но только самими корутинами(тредами). не бывает кооперативной многозадачности в одном треде.

https://en.wikipedia.org/wiki/Cooperative_multitasking

Cooperative multitasking, also known as non-preemptive multitasking, is a computer multitasking technique in which the operating system never initiates a context switch from a running process to another process. Instead, in order to run multiple applications concurrently, processes voluntarily yield control periodically or when idle or logically blocked. This type of multitasking is called cooperative because all programs must cooperate for the scheduling scheme to work. 

а вытесняющая многозадачность - это переключение не тредами, в внешним к ним диспетчером.

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

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

Я лучше продолжу дискуссию с теми, кто понял зачем в примере sleep.

windows10 ★★★★★
() автор топика

Возможно спрошу криворуко

И таки спросил криворуко!

Я правильно понял, что ты спрашиваешь как в коде вызвать 2 функции каждая из которых ждет выполнения другой? Можно пример зачем кому-то нужно писать такие функции, они ж бесполезны?

ya-betmen ★★★★★
()
Ответ на: комментарий от windows10

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

Gtk я давно не трогал, не помню как это делается там, но общий подход - тяжелая задача выполняется в отдельном потоке и по мере необходимости кидает сигналы/ивенты в общий event loop. В основном потоке твой гуй разбирает эти ивенты и обновляет свой стейт.

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

Не знаю почему, но эта функция срабатывает только после отработки всей функции

Ну так GTK требует процессор чтобы отрисовать интерфейс, а ты ему не даёшь, глубоко уходишь в сканирование каталогов. Запускай сканирование в отдельном потоке, иначе это никак не сделать. У GTK свой эвентлуп (движок асинков, про который я говорил), и он с большой вероятностью не умеет в асинхронные файловые операции (на линуксе это вообще требует io_uring и свежего ядра, раньше кроме отдельного треда никак нельзя было).

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

продолжай. счас тебя затащут в потемки awaitoв, сами там заплутают с «кооперативной многозадачностью». и научат писать вырвиглазный косорукий код.

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

Не знаю почему, но эта функция срабатывает только после отработки всей функции, т.е. по завершению цикла перебора вложенных субдиректорий. Ну и соответственно выводит только название последней директории.

Почитай про gtk event loop

anonymous
()
Ответ на: комментарий от ya-betmen

Я правильно понял, что ты спрашиваешь как в коде вызвать 2 функции каждая из которых ждет выполнения другой? Можно пример зачем кому-то нужно писать такие функции, они ж бесполезны?

Да, ты правильно понял. Пример я уже написал выше. Напишу еще раз.

Есть алгоритм рекурсивного поиска файлов начиная с текущей директории. Там может быть 10 файлов, а может быть и 10 тысяч. Такая себе комбинация cd и ls.

Задача: выводить промежуточные данные на экран. Для этого в середине алгоритма стоит Функция_Вывода_Текущей_Директории_На_Экран.

Проблема: Функция_Вывода_Текущей_Директории_На_Экран отрабатывает только тогда, когда алгоритм завершился и выводит последнее значение на экран.

Причина: кривизна Функции_Вывода_Текущей_Директории_На_Экран - но ее писал не я, это часть GTK и повлиять на нее я не могу.

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

Gtk я давно не трогал, не помню как это делается там, но общий подход - тяжелая задача выполняется в отдельном потоке и по мере необходимости кидает сигналы/ивенты в общий event loop. В основном потоке твой гуй разбирает эти ивенты и обновляет свой стейт.

О, благодарю !

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

Ну так GTK требует процессор чтобы отрисовать интерфейс, а ты ему не даёшь, глубоко уходишь в сканирование каталогов. Запускай сканирование в отдельном потоке, иначе это никак не сделать. У GTK свой эвентлуп (движок асинков, про который я говорил), и он с большой вероятностью не умеет в асинхронные файловые операции (на линуксе это вообще требует io_uring и свежего ядра, раньше кроме отдельного треда никак нельзя было).

Значит буду колупать GTK, спасибо.

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

Условно, ты можешь после каждого прочитанного файла вызвать что-то вроде Gtk.ProcessEvents (не знаю как конкретно), и интерфейс будет обновляться, но всё же будет притормаживать, потому что часть времени процесс тупо ждёт ядро на каком-нибудь fread. Поэтому обычно основной тред с Gtk стараются никак вообще не блокировать (точнее он там сам блокируется на сообщения оконной системы чтобы мгновенно на них реагировать), и всё остальное в дополнительные треды уносить. Сделай во втором треде очередь заданий и наваливай туда из Gtk задания, получай другой очередью статусы (какой файл сейчас в работе) и будет хорошо, без тормозов, как должно быть.

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

незачёт, придёшь на пересдачу через полгода

там где ты доцент, я профессор. мне даже интересно, как ты со своими однотредами и стеклесс «корутинами», будешь разруливать аппу с гуем и работой с фс.

очевидно, что там полновесный тред гуя и полновеснеые треды или воркеры для прочих действий, и даже не стекфулл корутины. и прокидывают они друг другу мессаги по асинхронным очередям.

куда ты залезешь там с корутинами куцыми своими, деревянная ты голова. лучше ичезни насовсем.

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 1)
Ответ на: комментарий от windows10

Да, ты правильно понял.

Вот из дальнейшего описания я понял, что не так понял.

Выше правильно сказали, скидывай результаты в отдельное место, будешь его в гуевом потоке рисовать, а данные туда наливай из другого потока.

Если ты в гуевый поток залез то пока работа не закончена ничего не покажешь.

ya-betmen ★★★★★
()