Программирование на C (Си) в Linux (часть 2)
Вставка
- Опубліковано 2 жов 2024
- Сегменты памяти процесса и их права доступа, порождение процессов системным вызовом fork() и принцип COW (copy-on-write), порождение нитей pthread
Об этом и о многом другом см. books.google.r...
Долго и упорно бился с ошибкой из-за вызова неизвестных функций: pthread_create() и pthread_join(). Проблема решилась просто - в Makefile указал ещё и LDFLAGS=-lpthread, получилось следующее (спасибо за наводку авторам на StackOverfow):
CFLAGS=-Wall -pthread
LDFLAGS=-lpthread
После этого всё отлично скомпилировалось и собралось :-)
Спасибо, Дмитрий, за интересный урок. Это стало отправной точкой для дальнейшего изучения программирования под Linux.
P.S.: gcc version 9.3.0 при компиляции выносит глобальные константы из секции с исполняемым кодом (r-xp) в отдельную секцию (r--p). Радует, что разработчики делают работу над ошибками :-)
Абалденно.
Большое спасибо Дмитрий! Очень помогло. Теперь все стало по местам в голове :)
Отличная подача, главное это сочетание теории и практики. Вопрос который не дает покоя, что это за заголовочные файлы, что из себя представляют и зачем нужны? С библиотеками или shared object понятно, там за тебя написаны программы, которые использует твоя программа. Что за заголовочные файлы и почему они не библиотека, если их функция одинакова как я понимаю? А еще бывают devel пакеты, тоже непонятно для чего, заголовочные файлы библиотеки?
Заголовочные файлы содержат описания типов данных, которыми манипулирует библиотека и декларации ее функций, котороые можно вызывать. Все это нужно копилятору для того, что бы проверить *правильность* использования этой библиотеки программистом в ее программе.
Любую библиотеку можно легко использовать *без* заголовочных файлов, но за правильность тогда никто не поручится и вся отвественность тогда будет на программисте. А *с* заголовочными файлами компилятор может произвести некоторые проверки.
В devel пакетах действительно содержатся заголовочные файлы библиотеки и "компоновочное имя" самой библиотеки, а зачастую еще и варинат тойже библиотеки для статической линковки - см. asciinema.org/a/198815
Спасибо!
между первой частью и второй есть какая то пропасть =))))
и у меня в (gcc v 8.3.0 Debian (8,3,0-6) ) глобальная переменная во всех случаях r--p,
а еще есть ? =) интересно черт возьми =) я просто обязан теперь книгу купить =)
я стал ближе к написанию змейки в терминале )))
большое спасибо было очень увлекательно.
Не, глобальная не может быть r--p. Только rw-p :)
Очень интересно. Только Я вот не понял, откуда брать код, как эту программу логически самому построить? Что посмотреть?
Есть такая наука о том как писать программы - программирование.
Что думаете о языке Golang как замену C ?
@@vinar9232 думаю что замена C/C++ этo rust, раз у D ничего не вышло
А программы написанные для виндовс будут также в /проц мапиться, запущенные под вайном? Или там другой порядок секций?
В /proc процессы, а не программы. Так как wine выполняет каждую win программу в своём linux процессе, то будут
Подскажите, не совсем понял как в переменную pid попадают 2 значения. У меня в голове такая модель - переменная поименованная область памяти и получается соответствие имени значению. За счёт каких промежуточных звеньев имя видит два значения? Какова схема этого явления?
В каждом процессе это своя именованная область памяти, всего процессов два - родитель и ребенок. Собственно две области - два значения, по одному на процесс.
@@DmitryKetov С зтим понятно, но как эти два значения хранятся в одной переменной pid. В чем секрет? 2 области , 2 значения, 2 процесса , а переменная 1 - pid. Или как то эта переменная специфическим образом обращается к этим двум областям? Уж простите Дмитрий, что глупые вопросы задаю.
Переменная это есть "именованная область памяти". Имя - одно, области для хранения - две.
Супер. Все понятно. Хотелось бы спросить Будет ли еще разбор программирования на Си в Линуксе?
Да, будет. Пишите, о чем было бы интересно узнать.
Вы реально крут ! Подписываюсь на ваш канал и жду ваших видео с нетерпением ...
Очень интересно Си в Linux и тема разработки модулей ядра !
Очень много интересных тем уже подробно и главное доступно раскрыто. Хотелось бы увидеть еще что-нибудь про виртуализацию.
"Что-нибудь" это как-то бессмысленно :)
Литературы море. Зачем еще один велосипед?
@@DmitryKetov вывод графики, пока без графических библиотек, например для написания собственного рендера методом обратной трассировки
глобальная константная переменная вроде и должна попадать в секцию кода. Секция кода вроде для нескольких экземпляров программы остается одна, когда для всех остальных секций выделяется память на каждый экземпляр. А так как константная глобальная переменная неизменно присутствует в каждом экземпляре, то чтобы не выделять лишнюю память она находится в секции кода. Насколько я правильно помню. П.с. я только начал изучать программирование, могу ошибаться.
Нет, не должна. В .text только исполняемый код ибо право на исполнение. Что касается страниц памяти любых файлов (не только elf) то все они будут лежать в памяти страничного кэша один раз покуда их страницы не подвергнутся изменению, сколько бы процессов с файлом не работало.
@@DmitryKetov Секция кода создаётся для хранения исполняемого машинного кода, из которого, собственно говоря, и состоит исполняемая программа. Естественно, область памяти, выделенная под секцию кода, доступна задаче на исполнение. С другой стороны, операционная система не позволяет пользовательским задачам модифицировать содержимое секции кода; попытка задачи сделать такую модификацию рассматривается как нарушение защиты памяти. Сделано это по достаточно простой причине: если в системе одновременно запущенно в виде задач несколько экземпляров одной и той же программы, операционная система обычно хранит в физической памяти только один экземпляр машинного кода такой программы. Это верно даже в случае, если запущенные задачи принадлежат разным пользователям и имеют разные полномочия в системе. Если одна из таких задач модифицирует "свою" секцию кода, очевидно, что это помешает работать остальным - ведь они используют (физически) ту же самую секцию кода. Однако на чтение секция кода доступна, так что её можно использовать не только для кода как такового, но и для хранения константных данных - такой информации, которая не изменяется во время выполнения программы.
А.В. Столяров.
Программирование. Введение в профессию. Том 2: Низкоуровневое программирование.
стр.41
@@DmitryKetov также и строковые литералы.
А.В. Столяров.
Программирование. Введение в профессию. Том 2: Низкоуровневое программирование.
стр.265
@@АлександрНовиков-я3ц Опыт - вершина познания (с) Проведите собственными руками и узрите :)
@@DmitryKetov Проверял, у меня не попадало в секцию кода. Однако в книге и написано может, а не должно, что мы и увидели на вашем примере. Ещё интересный пример можно было провести создав указатель на неконстантную область памяти, присвоив ему адрес глобальной константной переменной, приведя к (void *). И посмотреть что указатель действительно указывает на тот же адрес памяти что и у глобальной переменной. При попытке изменить значение глобальной переменной через указатель программа компилируется, но при запуске программы выдаёт ошибку сегментирования.
А видео очень крутое( и первая и вторая часть). Спасибо.
А как распределить процессорное время между потоками? Например, первый выполняется раз в миллисекунду, второй раз в 50 миллисекунд ?
Смотря как потоки реализованы в ядре или в userspace. В Линукс они в ядре существуют и воспринимаются им как некоторое универсальное понятие "задача". Ну и есть разные алгоритмы планирования
Краткий ответ - а никак, потому что незачем.
@@DmitryKetov Как незачем? А если это веб-сервер и имеется поток диспетчера и два рабочих потока, которые находятся в состоянии готовности. Какой поток выбрать следующим?
@@fwd8789 В исходном вопросе про ДОЛЮ времени, а у вас про ПОРЯДОК, а это две большие разницы, см. ua-cam.com/video/v7gsUPKcCQc/v-deo.html ua-cam.com/video/Vbl0Rk_oZW4/v-deo.html я эту разницу студентам не раз втолковывал, у них даже курсовик был 😂
@@DmitryKetov Спасибо. Сейчас перечитал у Таненбаума, что потоку выделяется квант времени, по истечении которого его работа приостанавливается, либо пока он не заблокируется вводом-выводом.
а как форк() умудряется возвратить 0 в дочерний процесс? он что - волшебник и все знает?
Типа того :)
@@hvac_vdk О черт! А что, если PID 0 уже занят в этот момент?
@@fwd8789 А 0 он не имеет смысла, поэтому не занят. Нет такого процесса, у которого pid=0
@@DmitryKetov Спасибо
@@DmitryKetov Стоп, а если форк присваивает PID=0, то как потом PID становится валидным идентификатором процесса? Кто его из нуля превращает в... заурядный номер процесса?