Потоки

ProFrager

Знаток
Проверенный
1. критические секции быстрее, им не нужно лезть на 0-й уровень привилегий, поскольку они работают только внутри одного процесса
проверял?)
то, как ты программируешь многопоточность - каменный век. есть более высокоуровневые парадигмы, и их можно реализовать даже если ты привязан к c++
чем ниже уровень, тем более управляемые и быстрые программы получаются. По сему ненавижу языки выше или равные уровню С++ (при этом чистый си считаю идеальным по всем параметрам).
 

SotM

Участник
Проверенный
Я то проверил, но как-то получается наоборот. Запускал 10 раз подряд exeшник с мьютексами, а затем 10 раз с крит.секциями.
У меня в тесте критические секции медленнее, чем мьютексы на 2%. Странно.

Изменил пару мест в исходнике, чтобы попытаться нагрузить проц хоть чем-то:
[source="c"]#define MaxLoopElements 10000

int RandomWait( void )
{
double result1, result2;
int i, j;

for ( i = 0; i < MaxLoopElements; i++ )
{
result1 = (double)( i * i );
for ( j = 0; j < MaxLoopElements; j++ )
result2 = result1 / (double)j;
result2 = sqrt( result1 );
}

return 0;
}[/source]
 

Булат Зиганшин

Developer
Модератор
знаю. иначе бы их полностью можно было заменить мьютексами


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

я к примеру на хаскеле и на с++ делал многопоточные программы. даже при использовании одинакового подхода c++ очень неудобен из-за того, что все ресурсы надо освобождать явно, для этого отслеживать когда что закончилось. на хаскеле например если в поток больше не будет чтения/записи, то операция на втором его конце просто вылетает с исключением, что позволяет автоматом завершить весь тред и освободить используемые в нём ресурсы

Добавлено через 18 минут
Я учился по примерам с инета Это очень ясный и простой пример, может кому-то еще он поможет.
А что ты предлагаешь? Мне аж интересно, всегда есть место для улучшений.
ага. это очень хороший пример того, что используя низкоуровневые средства, можно ошибиться даже в программе из 4 строчек

прочти книгу "взаимодействующие последовательные процессы" (communicating sequential processes), она есть в инете
 

ProFrager

Знаток
Проверенный
не раньше, чем ты тоже научишься исполнять миллиарды операций в секунду. а до того ты просто будешь зря тратить время. ну а данный вопрос отношения к языку вообще не имеет, речь в первую очередь о парадигме программирования, а во вторую уже о том, что в/у языки упрощают использование в/у парадигм
я к примеру на хаскеле и на с++ делал многопоточные программы. даже при использовании одинакового подхода c++ очень неудобен из-за того, что все ресурсы надо освобождать явно, для этого отслеживать когда что закончилось. на хаскеле например если в поток больше не будет чтения/записи, то операция на втором его конце просто вылетает с исключением, что позволяет автоматом завершить весь тред и освободить используемые в нём ресурсы
об этом спорили, спорят и будут спорить, и все останутся при своих мнениях) ИМХО выокоуровненные языки для debug версии, низкоуровненные - release.

Добавлено через 13 минут
1. критические секции быстрее, им не нужно лезть на 0-й уровень привилегий, поскольку они работают только внутри одного процесса
и плюс на сколько я представляю работу системы, ей разницы абсолютно никакой нет - в одном потоке все это происходит или в нескольких, функция распределения приоритетов тредов одна, толко для отдельного потока еще и фильтр именно для этого потока будет стоять. Все треды в сотнях запущенных процессах все равно выполняются одновременноб ну точнее последовательно, их переключает менеджер тредов, и вот как раз этот менеджер и руководствуется приоритетом каждого процесса и отдельного треда при распределении процессорного времени. А любая команда ожидания системного процесса оседает в том же менеджере тредов. Соответственно получается между критическими секциями и всеми остальными функциями управления тредами разниц никакой, кроме как совсем небольшой из-за разницы в реализации конкретного метода.
 

Булат Зиганшин

Developer
Модератор
1. спорить об этом могут только те, кому важен не результат, а процесс. профессионалы делят по-другому - каждая задача должна решаться на наиболее высоком приемлемом уровне. в частности, многопоточность гораздо лучше делать на том же хаскеле, проблема только в том, что его рантайм добавляет 200-400 кил к exe-файлу. там, где эти лишние килобайты нельзя позволить, придётся использовать более низкоуровневый C++. аналогично, в задаче, обрабатывающей десятки миллионов сообщений в секунду, нужно использовать lock-free структуры синхронизации, если же речь идёт о десятках тысяч сообщений, то вполне сойдёт обычная очередь

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

2. я же сказал - крит. секциям не нужно заходить в ядро, в частности в менеджер процессов. зачем? всё что там требуется - приостановить обработку других потоков, пытающихся одновременно ворваться в ту же крит. секцию. для этого делается цикл типа

while (critVar!=0);
critVar=1;
// мы внутри крит. секции...
critVar=0;
 

ProFrager

Знаток
Проверенный
Булат Зиганшин,
я же сказал - крит. секциям не нужно заходить в ядро, в частности в менеджер процессов. зачем? всё что там требуется - приостановить обработку других потоков, пытающихся одновременно ворваться в ту же крит. секцию. для этого делается цикл типа
функции крит секций внутри себя выполняют ту же waitforsingleobject, иначе этот поток ожидания будет жрать 1 ядро проца (что и делает твой пример), а крит секции этого не делают. Вывод: они являются теми же функциями ядра.
 

Булат Зиганшин

Developer
Модератор
вывод неверный. я написал упрощённый код только для демонстрации ненужности ухода в ядро. на самом же деле крит. секция делает сначала несколько проверок, затем при неудаче уходит в ядро. при этом вероятность ухода в ядро мала - подумай почему

я тебе так и буду продолжать построчно пересказывать multithreading manuals??
 

Булат Зиганшин

Developer
Модератор
вот для сравнения, как это выглядит на хаскеле:

main = do q <- newChanWithData [1..1000]
for [1..4] $ forkIO $ (readChan q >>= print)

это всё! программа создаёт канал, кидает в него числа от 1 до 1000, затем создаёт 4 потока, которые параллельно читают числа из канала и печатают их

хотя на самом деле я тут опустил ожидание завершения потоков (или хотя бы данных в канале). тем не менее можешь сравнить с сишным кодом :)

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

ProFrager

Знаток
Проверенный
Булат Зиганшин, а каковы накладные расходы для всего этого? Да, удобно и быстро кодить, не спорю, но для релиз-версии оно малопригодно. Если писать на си Arc.exe бы весил не более 500кб (на асме - еще в несколько раз меньше, но петерялась бы кроссплатформенность), плюс буст к быстродействию, хотя в данном случае у тебя на хескеле не основные алгортимы описаны, поэтому разница была бы небольшой. Но с этими сверхвысокими языками программирования мы лишь заставляем пользователей покупать все более крутые тачки, больше памяти и т.д. хотя раньше все то же самое можно было сделать в разы быстрее и меньше на низкоуровненных языках. Прогресс - это хорошо, но отходить от корней не стоит. Низкоуровненное программирование - это основа, винапи - это основа, мсдн - это основа.
 
Последнее редактирование:
Сверху