ВходНаше всё Теги codebook 无线电组件 Поиск Опросы Закон Воскресенье
22 декабря
1013270 Топик полностью
fk0, легенда (19.06.2020 15:27, просмотров: 1077) ответил LightElf на Ну вот есть у тебя абстракция write, пользуй ее и не ломай голову как она внутри устроена. Конкретная реализация write будет зависеть от OS, а конкретная реализация драйвера UART - от конкретного железа. А если не UART, а Ethernet - там будут другие реализации и другие драйвера. Будет ли там условная переменная, два семафора или отдельный сопроцессор с блекджеком и программистками - это вопрос конкретной реализации, а не фундаментальных принципов.
В таком варианте вместо запрета прерываний следует использовать мьютекс -- они для этого и существуют. Причём мьютексов связанных с разными и независимыми защищаемыми наборами данных может быть много, а флаг прерываний -- один всего. Мьютекс более эффективен. Более того, запрещать прерывания более чем несколько тактов -- дичь! Вопрос же не как критическую секцию сделать, а как сделать атомик (на основе которого уже можно сделать тот же мьютекс или критическую секцию). 

Вариант для __sync_fetch_and_add, __sync_val_compare_and_swap и т.п. write() как есть очевидно это совершенно не то, что запись в кольцевой буфер: во-первых буфер тебе может предоставить память (куда ты printf'ом распечатаешь), а для write память нужно выделить, во-вторых и это основное, запись в буфер если он не переполнен всегда легковесна, а write -- это всегда тяжелый syscall. Зачем спрашивается в libc fwrite(3) буферизованый (при размер буфера до 16-32кБайт, по сравнению с вариантом без буфера, скорость увеличивается на порядок запросто, потом увеличивать размер буфера особого смыла нет -- увеличение скорости только из-за экономии на сисколлах). Да, ты можешь сказать используй printf совместно с setvbuf. Но libc не умеет работать _асинхронно_, там запись буфера синхронная. Вначале ты пишешь быстро, потом оно натыкается на необходимость сделать flush и ты ничего не делаешь и ждёшь. В то время, как вариант с кольцевым буфером пишет в фоне параллельно. Асинхронного ввода-вывода в libc считай что нет. Возможно пример неудачный. Первое что пришло в голову, зачем нужна условная переменная. Другой пример: допустим, тебе нужен RWLock. Допустим, есть некоторая база данных, да что угодно там, что из многих потоков и часто читается параллельно и иногда пишется. С обычным мьютексом у тебя все чтения перестанут быть параллельными и станут последовательными. И не дай бог читатели под мьютексами вызывают блокирующие функции. В итоге CPU load низкий, все спят и ждут пока один поток закончит. Всё работает медленно. RWlock такую ситуацию исправляет, т.к. позволяет всем читателям работать одновременно. Но когда пишущему потоку нужно записать -- все кто пытается завладеть читающим локом должны заблокироваться, те кто уже владеет -- закончить работу, и тогда можно писать. Это стратегия дающая приоритет пишущему потоку. Со стратегией с приоритето читателей не очень, т.к. писатель рискует зависнуть в потенциале навсегда (если читают непрерывно и много). Вопрос, как сделать RWLock если его операционка не предоставляет? Ответ есть в википедии и там опять условная переменная. Вариант с семафором, который заранее знает сколько у него будет читателей -- не предлагать, не реалистично (семафор инициализируем числом читателей, в read-lock'e ждем семафор, в write-lock'e опустошаем семафор пока не будет занят, на выходе нужное число раз его постим).

[ZX]