Программирование PC Linux: функции для создания многопоточного консольного приложения Mon, July 15 2024  

Поделиться

Нашли опечатку?

Пожалуйста, сообщите об этом - просто выделите ошибочное слово или фразу и нажмите Shift Enter.

Linux: функции для создания многопоточного консольного приложения Печать
Добавил(а) microsin   

В этой статье приведен общий обзор функций POSIX.4a Single UNIX Specification, Version 3, предназначенных для создания многопоточных приложений на языке C/C++. Все они декларированы в заголовочном файле pthread.h [1].

pthread_create. Создает из запущенного (обычно это функция main приложения) процесса новый поток (thread).

#define _OPEN_THREADS
#include < pthread.h>
int pthread_create(pthread_t *thread,
                   pthread_attr_t *attr,
                   void *(*start_routine) (void *arg),
                   void *arg);

SUSV3:

#define _UNIX03_THREADS
#include < pthread.h>

int
pthread_create(pthread_t * __restrict__thread, const pthread_attr_t *attr, void *(*start_routine) (void *arg), void * __restrict__arg);

Атрибуты нового потока определены в параметре attr, который был создан вызовом функции pthread_attr_init(). Если в attr был передан NULL (что используется довольно часто), то используются атрибуты по умолчанию (для информации по атрибутам потока и их значениям по умолчанию см. описание функции pthread_attr_init). Если атрибуты, указанные параметром attr, были изменены позже, то эти изменения никак не повлияют на созданный поток.

Тело работающего потока создается в функции, на которую указывает start_routine, у этой функции только один аргумент arg. Если вызов pthread_create завершился успешно, то по указателю thread будет возвращен уникальный ID созданного потока. Если же вызов оказался неудачным (когда функция pthread_create возвратит -1), то никакой поток не создается, и содержимое ячейки памяти, на которую указывает thread, будет неопределенным.

По умолчанию системой ограничено максимальное количество создаваемых потоков, что определено значением MAXTHREADS в поле parmlib BPXPRMxx. Реальное количество потоков зависит от размера приватной области памяти ниже 16M [2]. Функция pthread_create проверяет адресное пространство перед созданием нового потока. Реалистичный предел для количества создаваемых потоков - от 200 до 400.

Специальное поведение для C++: из-за того, что соглашения по вызовам (linkage conventions) языков C и C++ несовместимы, то pthread_create не может принять указатель на функцию C++ в качестве параметра start_routine. Если вы попытаетесь передать в pthread_create указатель на функцию C++, то компилятор выдаст ошибку. Вы можете передать C или C++ функцию, если декларируете её как "C".

Запущенный поток предоставляет границу по отношению к области обработки исключений try-throw-catch. Исключение throw, которое сработало в функции потока start_routine (или в функции, которая была из потока вызвана), раскручивает стек вверх до момента вызова start_routine включительно (или до кода обработчика исключения). Раскручивание стека не будет выходить за рамки start_routine, обратно в родительский поток, который создал start_routine. Если исключение не обработано, то будет вызвана terminate().

Стек исключения (для try-throw-catch) основывается на потоке. Выбрасывание исключения (одиночное или повторное) не влияет на обработку исключений другого потока кроме случаев, когда событие исключения не было перехвачено и обработано.

Возвращаемое значение: в случае успешного завершения функция pthread_create() вернет 0. Иначе pthread_create() вернет -1 и установит при этом переменную errno в одно из следующих значений кода ошибки:

EAGAIN: в системе недостаточно ресурсов для создания потока.
EINVAL: в указателе thread передан null.
ELEMULTITHREADFORK: pthread_create() была вызвана из дочернего процесса, созданного вызовом fork() из многопоточного процесса (multi-threaded process). Этот дочерний процесс имеет ограничение - ему нельзя становиться многопоточным (multi-threaded).
ENOMEM: недостаточно памяти для создания потока.

Пример использования pthread_create:

#define _OPEN_THREADS
#include < pthread.h>
#include < stdlib.h>
#include < stdio.h>

void
*thread(void *arg)
{ char *ret; printf("thread() entered with argument '%s'\n", arg); if ((ret = (char*) malloc(20)) == NULL) { perror("malloc() error"); exit(2); } strcpy(ret, "This is a test"); pthread_exit(ret);
}   main()
{ pthread_t thid; void *ret;   if (pthread_create(&thid, NULL, thread, "thread 1") != 0) { perror("pthread_create() error"); exit(1); }   if (pthread_join(thid, &ret) != 0) { perror("pthread_create() error"); exit(3); }   printf("thread exited with '%s'\n", ret);
}

Вывод примера:

thread() entered with argument 'thread 1'
thread exited with 'This is a test'

Связанные функции: pthread_exit (выход из потока), pthread_join (ожидание завершения потока).

pthread_attr_init. Инициализирует атрибуты потока по умолчанию.

#define _OPEN_THREADS
#include < pthread.h>

int
pthread_attr_init(pthread_attr_t *attr);

SUSV3:

#define _UNIX03_THREADS
#include < pthread.h>

int
pthread_attr_init(pthread_attr_t *attr);

Вызов pthread_attr_init заполнит структуру attr значениями атрибутов по умолчанию, чтобы они использовались для создания нового потока. Эти значения следующие:

stacksize: размер стека, наследуется из runtime-опции STACK.
detachstate: Undetached.
synch: Synchronous.
weight: Heavy

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

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

Замечание: приложение XPLINK использует 2 стека, один растет в сторону увеличения адреса (upward-growing stack), а другой в сторону уменьшения адреса (downward-growing stack). Значение "stacksize" всегда относится к размеру upward-growing стека. Размер downward-growing стека наследуется из runtime-опции THREADSTACK.

Возвращаемое значение: в случае успеха pthread_attr_init() вернет 0. Если вызов был неудачным, то будет возвращено значение -1, и переменная errno установится в одно из следующих кодов ошибки:

ENOMEM: недостаточно памяти для создания объекта атрибутов потока.

Специальное поведение для Single UNIX Specification, Version 3: в случае неудачи pthread_attr_init() вернет код ошибки, описывающий её причину.

Пример использования pthread_attr_init:

#define _OPEN_THREADS
#include < stdio.h>
#include < pthread.h>

void
*thread1(void *arg)
{ printf("hello from the thread\n"); pthread_exit(NULL);
}

int
main()
{ int rc, stat; pthread_attr_t attr; pthread_t thid;   rc = pthread_attr_init(&attr); if (rc == -1) { perror("error in pthread_attr_init"); exit(1); }   rc = pthread_create(&thid, &attr, thread1, NULL); if (rc == -1) { perror("error in pthread_create"); exit(2); }   rc = pthread_join(thid, (void *)&stat); exit(0);
}

Связанные функции: pthread_attr_destroy (уничтожит объект атрибутов потока), pthread_create (создание потока).

pthread_detach. "Отсоединяет" поток от родительского потока. Позволяет повторно использовать хранилище для потока, ID которого сохранен, когда поток завершается. Это хранилище восстанавливается при выходе из процесса, независимо от того, был ли поток отсоединен, и может включать хранилище для значения возврата потока. Если поток не завершен, то pthread_detach() не приведет к его завершению.

#define _OPEN_THREADS
#include < pthread.h>

int
pthread_detach(pthread_t *thread);

SUSV3:

#define _UNIX03_THREADS
#include < pthread.h>

int
pthread_detach(pthread_t thread);

Параметр thread имеет тип данных pthread_t, который уникально идентифицирует поток. Это значение создается с помощью вызова pthread_create(), и используется приложением в вызовах функций, которые требуют на входе идентификатор потока.

Возвращаемое значение: в случае успеха pthread_detach() вернет 0. Иначе pthread_detach() вернет -1, и установит errno в один из следующих кодов ошибки:

EINVAL: предоставлено недопустимое значение thread.
ESRCH: значение, указанное thread, относится к потоку, который уже отсоединен.

Специальное поведение для Single UNIX Specification, Version 3: в случае неудачи pthread_detach() вернет код ошибки, описывающий её причину.

Пример использования pthread_detach:

#define _OPEN_SYS
#define _OPEN_THREADS
#include < pthread.h>
#include < stdlib.h>
#include < stdio.h>

void
*thread(void *arg)
{ char *ret; printf("thread() entered with argument '%s'\n", arg); if ((ret = (char*) malloc(20)) == NULL) { perror("malloc() error"); exit(2); } strcpy(ret, "This is a test"); pthread_exit(ret);
}   main()
{ pthread_t thid; void *ret;   if (pthread_create(&thid, NULL, thread, "thread 1") != 0) { perror("pthread_create() error"); exit(1); }   if (pthread_join_d4_np(thid, &ret) != 0) { perror("pthread_create() error"); exit(3); }   printf("thread exited with '%s'\n", ret);   if (pthread_detach(&thid) != 0) { perror("pthread_detach() error"); exit(4); }
}

Вывод примера:

thread() entered with argument 'thread 1'
thread exited with 'This is a test'

Связанные функции: pthread_join (ожидание завершения потока).

pthread_self. Возвратит идентификатор текущего потока (thread ID), из которого была вызвана функция pthread_self.

#define _OPEN_THREADS
#include < pthread.h>

pthread_t pthread_self(void);

Возвращаемое значение: для функции pthread_self не существует документированных кодов ошибки для установки переменной errno. Используйте perror() или strerror(), чтобы определить случай ошибки.

Пример использования pthread_self:

#define _OPEN_THREADS
#include < pthread.h>
#include < stdio.h>

pthread_t thid, IPT;

void
*thread(void *arg)
{ if (pthread_equal(IPT, pthread_self())) puts("the thread is the IPT...?"); else puts("the thread is not the IPT");   if (pthread_equal(thid, pthread_self())) puts("the thread is the one created by the IPT"); else puts("the thread is not the one created by the IPT...?");
}   main()
{ IPT = pthread_self(); if (pthread_create(&thid, NULL, thread, NULL) != 0) { perror("pthread_create() error"); exit(1); }   if (pthread_join(thid, NULL) != 0) { perror("pthread_create() error"); exit(3); }
}

Вывод примера:

the thread is not the IPT
the thread is the one created by the IPT

Связанные функции: pthread_create (создание потока), pthread_equal (сравнение идентификаторов потока).

[Ссылки]

1. pthread.h site:ibm.com.
2. pthread_create() сreate thread site:ibm.com.
3. Создание и ожидание выполнения потоков site:learnc.info.

 

Добавить комментарий


Защитный код
Обновить

Top of Page