Такие читатели, как вы, помогают поддерживать MUO. Когда вы совершаете покупку по ссылкам на нашем сайте, мы можем получать партнерскую комиссию. Читать далее.

В Linux вы можете создавать и управлять потоками на C/C++, используя библиотеку потоков POSIX (pthread). В отличие от других операционных систем, в Linux нет большой разницы между потоком и процессом. Вот почему Linux часто называет свои потоки легковесными процессами.

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

История использования потоков в Linux

До Linux версии 2.6 основной реализацией потока был LinuxThreads. Эта реализация имела значительные ограничения с точки зрения производительности и операций синхронизации. Ограничение на максимальное количество потоков, которые могут выполняться, ограничивало их до 1000.

В 2003 году команде разработчиков из IBM и RedHat удалось создать Нативная библиотека потоков POSIX (NPTL) проект доступен. Впервые он был представлен в RedHat Enterprise версии 3 для решения проблем с производительностью виртуальной машины Java в Linux. Сегодня библиотека GNU C содержит реализации обоих механизмов многопоточности.

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

Вы можете найти информацию о потоке для любого запущенного процесса в файлах под /proc//task. Это стандартное место для информации о процессе в разделе стандарт Linux procfs. Для однопоточных приложений окажется, что в этом каталоге есть запись задачи с тем же значением, что и PID.

Рабочая логика потоков

Потоки похожи на процессы, запущенные в данный момент в операционной системе. В однопроцессорных системах (например, микроконтроллерах) ядро ​​операционной системы имитирует потоки. Это позволяет транзакциям выполняться одновременно через срезы.

Одноядерная операционная система может реально запускать только один процесс за раз. Однако в многоядерные или многопроцессорные системы, эти процессы могут выполняться одновременно.

Создание потока в C

Вы можете использовать pthread_create функция для создания нового потока. pthread.h Заголовочный файл включает определение своей подписи вместе с другими функциями, связанными с потоком. Потоки используют то же адресное пространство и файловые дескрипторы, что и основная программа.

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

Когда вы используете функции библиотеки pthread, вы должны убедиться, что компилятор связывает пнить библиотеку в свой исполняемый файл. При необходимости вы можете указать компилятору связать библиотеку с помощью параметра вариант:

gcc -о тест test_thread.c -lpthread

Функция pthread_create имеет следующую сигнатуру:

интpthread_create(pthread_t *нить, константаpthread_attr_t * атрибут, пустота *(*start_routine)(пустота *), пустота *аргумент)

Возвращает 0, если процедура выполнена успешно. Если есть проблема, он возвращает ненулевой код ошибки. В приведенной выше сигнатуре функции:

  • нить параметр имеет тип pthread_t. Созданный поток всегда будет доступен по этой ссылке.
  • атрибут Параметр позволяет указать пользовательское поведение. Вы можете использовать серию специфичных для потока функций, начиная с pthread_attr_ установить это значение. Возможными настройками являются политика планирования, размер стека и политика отсоединения.
  • start_routine указывает функцию, которую будет выполнять поток.
  • аргумент представляет общую структуру данных, переданную функции потоком.

Вот пример приложения:

#включать
#включать
#включать
#включать

пустота *рабочий(пустота *данные)
{
уголь *имя = (уголь*)данные;

для (инт я = 0; я < 120; я++)
{
ты спишь(50000);
printf("Привет из темы, имя = %s\n", имя);
}

printf("Тема %s выполнена!\n", имя);
возвращатьсяНУЛЕВОЙ;
}

интосновной(пустота)
{
pthread_t т1, т2;
pthread_create(&th1, НУЛЕВОЙ, рабочий, "Х");
pthread_create(&th2, НУЛЕВОЙ, рабочий, "Ы");
спать(5);
printf("Выход из основной программы\n");
возвращаться0;
}

Типы резьбы

Когда поток возвращается из основной() функции в приложении, все потоки завершаются, и система освобождает все ресурсы, используемые программой. Аналогично, при выходе из любого потока с помощью команды типа Выход(), ваша программа завершит все потоки.

С pthread_join вместо этого вы можете дождаться завершения потока. Поток, использующий эту функцию, будет заблокирован до тех пор, пока ожидаемый поток не завершится. Ресурсы, которые они используют из системы, не возвращаются даже в таких случаях, как завершение присоединяемых потоков, незапланированное ЦП или даже неспособность присоединиться к ptread_join.

Иногда бывают ситуации, когда объединение с помощью pthread_join не имеет смысла; если невозможно предсказать, когда тред закончится, например. В этом случае вы можете гарантировать, что система автоматически вернет все ресурсы в точке возврата потока.

Чтобы добиться этого, вы должны начать соответствующие потоки с ОТДЕЛЬНЫЙ положение дел. При запуске потока ОТСОЕДИНИТЬ статус может быть установлен через значения атрибута потока или с помощью pthread_detach функция:

интpthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
интpthread_detach(pthread_t нить);

Вот пример использования pthread_join(). Замените основную функцию в первой программе на следующую:

интосновной(пустота)
{
pthread_t т1, т2;
pthread_create(&th1, НУЛЕВОЙ, рабочий, "Х");
pthread_create(&th2, НУЛЕВОЙ, рабочий, "Ы");
спать(5);
printf("выход из основной программы\n");
pthread_join (th1, НУЛЕВОЙ);
pthread_join (th2, НУЛЕВОЙ);
возвращаться0;
}

Когда вы скомпилируете и запустите программу, ваш вывод будет:

Привет из темы Y
Привет из темы Х
Привет из темы Y
...
Привет из темы Y
выход из основной программы
Привет из темы Х
...
Привет из темы Х
Тема Х готова!
Привет из темы Y
Тема Y готова!

Завершение потока

Вы можете отменить поток вызовом pthread_cancel, передав соответствующий pthread_t идентификатор:

интpthread_cancel(pthread_t нить);

Вы можете увидеть это в действии в следующем коде. Опять же, только основной функция другая:

интосновной(пустота)
{
pthread_t т1, т2;
pthread_create(&th1, НУЛЕВОЙ, рабочий, "Х");
pthread_create(&th2, НУЛЕВОЙ, рабочий, "Ы");
спать(1);
printf("> Отмена темы Y!!\n");
pthread_cancel (th2);
ты спишь(100000);
printf("> Отмена темы X!\n");
pthread_cancel (th1);
printf("выход из основной программы\n");
возвращаться0;
}

Зачем создаются темы?

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

Вы можете настроить ресурсы, которые вы выделяете потокам, которые вы создаете с помощью pthread. Это может быть настраиваемая политика планирования или вы можете выбрать алгоритмы планирования, такие как FIFO или Round-robin, если это необходимо.