Ассемблер на двух и более ядерном процессоре
Немного умею программировать на асме для микроконтроллеров AVR и 8051, и однажды родился вопрос: а как выглядит программа на ассемблере для двухядерного или более, процессора. Попытался себе это представить, и понял что не могу. Это однозадачная штука, как ни крути. В голове не укладывается, ни как это писать, ни как это транслировать. Объясните секрет, пожалейте дурака.
Ответы (1 шт):
В Windows усть такое понятие как поток-исполнения "Thread" (коротко - тред). Поскольку на системах х32 юзеру доступно половина адресного пространства из четырёх ~2 ГБ, то в одном своём приложении функцией CreateThread() мы можем создать макс.2000 тредов, т.к. в дефолте каждому из них выделяется по 1 МБ для стека. Теперь это приложение попадает в среду исполнения на произвольном компьютере. Если у него процессор 2-х и более ядерный, то системный планировщик потоков распределяет наши 2000 тредов поровну по всем исполнительным ядрам CPU, в результате чего они фактически исполняются параллельно по времени.
Здесь мы сталкиваемся с проблемой синхронизации работы всех потоков, т.е. чтобы не получилось так, что один поток что-то сохранил в глобальной переменной, а ничего не знающий об этом второй поток тут-же не подмял эту переменную под себя. Для этого существуют объекты синхронизации типа: семафоры, события, мутанты, эвенты. Поэтому в многопоточном коде советуют использовать только локальные переменные, которые никто у вас уже не заберёт, т.к. они распологаются в индивидуальном стеке каждого потока.
Если-же ядро у процессора одно, то планировщику придётся ставить в одну очередь все 2000 потоков приложения. В этом случае приложение остаётся то-же самое, только получаем иллюзию параллельного исполнения, т.к. треды будут исполняться в порядке очерёдности, по выделенному им кванту времени (в дефолте ~12 микро-сек). Вот скелет многопоточного приложения на ассемблере fasm:
.data
id1 dd 0 ;// переменные под ID потока
id2 dd 0
id3 dd 0
id4 dd 0
.code
start: invoke CreateThread,0,4096,thread_1,0,0,id1 ;// создаём нужное кол-во тредов..
invoke CreateThread,0,4096,thread_2,0,0,id2 ;// 4096 - это размер стека в байтах
invoke CreateThread,0,4096,thread_3,0,0,id3 ;// ThreadX - указатель на процедуру потока
invoke CreateThread,0,4096,thread_4,0,0,id4 ;// idX - идентификатор потока,
;// чтобы его можно было приостановить, закрыть и.п.
proc thread_1
;// ..... код потока
endp
proc thread_2
;// ..... код потока
endp
proc thread_3
;// ..... код потока
endp
proc thread_4
;// ..... код потока
endp