Pull to refresh

Comments 28

Спасибо за статью. Стоит добавить, что pthreads также предлагает примитивы синхронизации, в частности мьютексы — см man pthread_mutex_init и далее по ссылкам.
Простенько и со вкусом. Отлаживать можно через gdbserver из Visual Studio 2015/17. Хотя и через Eclipse никто не запрещает.
В Линуксе всё — процессы. То, что вы называете потоками — это те же процессы, которые делят между собой некоторые ресурсы, например, адресное пространство.

man 2 clone, например, CLONE_VM.
Вопрос терминологии. «Если это выглядит как утка, плавает как утка и крякает как утка, то это, возможно, и есть утка.» А как это уже внутри ядра реализвано это отдельный вопрос. Если реализация поменяется — название тоже менять?
В ядре реализацию никто не будет менять, т.к. это вопрос обратной совместимости. В ядре с этим строго.
Всегда есть возможность оставить слой совместимости, возможно появление параллельно другой реализации потоков. Да, такие вещи делают только в исключительных случаях. Но исключать возможность я бы не стал.
В ядре какой системы? POSIX и pthreads же не привязан к одному линуксу, а речь про них. В терминах ядра линукса вы абсолютно правы, но речь не про ядро линукса.
Вопрос терминологии, можно сказать что clone() c флагами CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SYSVSEM | CLONE_SIGHAND | CLONE_THREAD | CLONE_SETTLS | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID — метод создать тред в терминах сисколов ядра линукса. Здесь же речь про pthreads, а в нем это тред называется.
image
предельное значение ускорения при N стремящемся к бесконечности равно 4.


Это неверно. Надеюсь, остальное в вашей статье не так ошибочно…
Поправлюсь (хабр не дал возможность изменить комментарий — что за идиотские правила?!):

это верно только для соотношения 0.25/0.75 (потому, что 1/4 :) ), но, если величина параллельного кода > 99%, то тогда пресловутая формула стремится к 100 (при бесконечном числе процессоров).

Что, с «точки зрения банальной эрудиции» (а также формальной логики) есть полный бред — получается прямо какая-то скорость света в вакууме. Возможно, я и ошибаюсь, но мне кажется, что ускорить вычисления более чем в сто раз вполне реально.
Поправлюсь (хабр не дал возможность изменить комментарий — что за идиотские правила?!):
Правила как раз нормальные. А то появятся всякие «владельцы своего слова»: захотел — дал, захотел — забрал. А так — сразу видно кто — думает при написании комментариев, кто — нет.

Возможно, я и ошибаюсь, но мне кажется, что ускорить вычисления более чем в сто раз вполне реально.
Если у вас есть один процент, который обязательно нужно исполнять последовательно — то нет. А если такого участка кода нет, то да, разумеется — и закону Амдала это никак не противоречит…

это верно только для соотношения 0.25/0.75 (потому, что 1/4 :) ), но, если величина параллельного кода > 99%, то тогда пресловутая формула стремится к 100 (при бесконечном числе процессоров).
Если процент параллелизуемого кода > 99%, то формула может стремиться и к тысяче и к миллиону — посчитайте.

P.S. Если уж так хотелось написать «аффтар — дурак, статья — равно», то вы бы уж лучше придрались к тому, что он «закон Амдала» называет «закон Амдала». Выглядело бы всё равно не так жалко, как то, что вы тут изобразили…
Например 75% кода запускается параллельно, а 25% — последовательно.

Пропустить важное уточнение и ругать на основе этого статью?
Получается как в анекдоте про аквариум и логику.
Что будет, если завершение потока не перехватить вызовом pthread_join() и чем это отлично от сценария, при котором завершился отсоединенный поток?

Если это повторить много раз, то pthread_create() перестанет создавать потоки.
Мне одному кажется, что тут надо добавить ссылку хотя бы на pthread.h в POSIX?

Справедливое замечание, ссылку добавил.

Было бы полезно, если на хабре появится актуальная статья про std::thread (в сравнении с pthread), с оглядкой на кроссплатформеность и состояние реализаций на разных платформах.

Объясните, пожалуйста, зачем в таких функциях, как pthread_create() передается указатель на переменную, куда записать номер потока. Почему нельзя просто вернуть этот номер из функции?

pthread_t thread = pthread_create();
Потому что при ошибке она возвращает код ошибки. Всяко лучше, чем через errno.
Наверно, потому что pthread_create может вернуть ошибку?
Потому что все функции pthread API сделаны так, чтобы не пришлось ходить к нему же для получения errno (errno в многонитевом режиме это что-то вроде (*__errno_ptr()), где функция errno_ptr находит thread-local storage (TLS) данной нити и возвращает адрес errno в нём). Коды ошибки универсально возвращаются из функции, 0 означает отсутствие ошибки, другой код — конкретный номер ошибки.
И этот код надо проверять — несоздание нити в случае переполнения чего-нибудь это вполне обычная ситуация. Поэтому он возвращается напрямую, а идентификатор созданной нити — по указателю.
Потому что мы хотим узнать, отработала ли функция нормально (в данном случае — удалось ли создать поток). Т.е. pthread_create() возвращает код ошибки (или 0 в случае успеха). Если его не возвращать, то требовалось бы либо передавать этот код через одну из переменных, либо через какое-то глобальное значение. Возвращать статус исполнения — самый частый подход, поэтому его придерживались и здесь тоже.
Вы предлагаете подключать библиотеку так:
 -lpthread 


А если подключать так (без l вначале):
 -pthread 

Тогда подключатся потоко-безопасные функции…
man gcc


-pthread
Adds support for multithreading with the pthreads library. This option sets flags for both the preprocessor and linker.

Иными словами — -pthread == -D_REENTRANT -lpthread

А вот, кстати, интересно что со всем этим делать. Когда-то, давным-давно, на всяких AIX'ах и HP-UX'ах это было реально важно. Но сегодня — что в GNU/Linux, что в MacOS, что в Android нет никакой разницы.

Так стоит ли про это помнить или нет?

Иными словами — -pthread == -D_REENTRANT -lpthread
Не совсем так. На OpenBSD оно будет пределять -D_POSIX_THREADS, на AIX — -D_THREAD_SAFE, на FreeBSD — будет, ко всему прочему, использовать не libc.so, а libc_r.so и так далее. Сейчас посмотрел: на HP-UX'е нужно определять всё сразу: и -D_REENTRANT -D_THREAD_SAFE и ещё -D_POSIX_C_SOURCE=199506L!

Но вот конкретно на большинстве операционок на основе Linux'а — разницы нет!
Кажется, у вас есть неточности:
Solaris использовал M:N
M:N сейчас используется в DragonflyBSD: да, у нас теоретически неограниченное число тредов (как когда-то в солярке).
да, у нас теоретически неограниченное число тредов (как когда-то в солярке).
Неправда ваша, тётенька. Количество тредов — всегда ограничено, так как каждому положен свой стек. С учётом того, что в Linux в ядре только ядрёный стек новому треду и положен, больше ничего — практическая разница невелика. Ах, да, ещё номера могут для них кончится раньше, если на машине более 64TiB памяти… не знаю — такие системы, хотя бы в теории, DragonflyBSD поддерживает???
>а предельное значение ускорения при N стремящемся к бесконечности равно 4.

При N стермящейся к бесконечности — будет бесконечное ускорение.
Возможно имелось ввиду, что при F сремящемся к 100% в 4х ядерной системе ускорение будет равно 4
Нет, в тексте всё верно. 25% — не распараллеливающийся участок. Остальное бесконечно ускорится и выполнится мгновенно. Общее время станет 0.25 от того, что было — ускоренеи в 4 раза.
Точно, спасибо. запутался с 4ками.
Sign up to leave a comment.

Articles