Читаем QNX/UNIX: Анатомия параллелизма полностью

EPERM— вызвавший поток не является владельцем внутреннего мьютекса.

<p>Функции ожидания</p>

Ожидание выполнения условия для ждущей блокировки может выполняться в двух вариантах: простое ожидание и ожидание с установкой тайм-аута.

int pthread_sleepon_wait(const volatile void* addr);

int pthread_sleepon_timedwait(const volatile void* addr, uint64_t nsec);

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

<p>Ожидание завершения потока</p>

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

void* threadfunc(void* data) {

 ...

 return NULL;

}

...

// здесь создается нужное количество (N) потоков:

pthread_t tid[N];

for (int i = 0; i < N; i++)

 pthread_create(tid + 1, NULL, threadfunc, NULL);

// а вот здесь ожидается завершение всехпотоков!

for (int i = 0; i < N; i++)

 pthread_join(tid + 1, NULL);

При первом знакомстве с подобным шаблоном кода пугает то обстоятельство, что предписан такой же порядок ожидания завершения потоков, как и при их создании. И это при том, что порядок их завершения может быть совершенно произвольным. Но представленный шаблон верен: если некоторый ожидаемый в текущем цикле поток j«задерживается», а мы заблокированы именно в ожидании tid[j], то после завершения этого ожидаемого потока, которое когда-то все-таки наступит, мы «мгновенно» пробегаем все последующие i, для которых соответствующие tid[i]уже завершились ранее. Так что представленный шаблон корректен и широко используется на практике.

Примечание

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

Показанная схема синхронизации на завершении потоков не является примитивом синхронизации и не требует использования таковых, но она выводит нас на еще один тип примитивов — барьер.

<p>Барьер</p>

Барьер как раз и предназначен для разрешения выше обозначенной проблемы — ожидания условия достижения несколькими заданными потоками точки синхронизации. Достигнув этой точки, потоки освобождаются «одновременно» и уже с этой точки продолжают свое независимое развитие. «Классическая» схема использования барьера (именно в таком качестве он чаще всего и используется), неоднократно приводимая в описаниях, выглядит так (мы уже много раз использовали ее в примерах кода):

static pthread_barrier_t bfinish;

void* threadfunc(void* data) {

 // потоки что-то делают ...

 pthread_barrier_wait(&bfinish);

 return NULL;

}

int main(int argc, char *argv[]) {

 int N = ...; // будем создавать N идентичных потоков

 if (pthread_barrier_init(&bfinish, NULL, N + 1) != EOK)

  perror("barrier init"), exit(EXIT.FAILURE);

 for (int i = 0; i < N; i++)

  if (pthread_create(NULL, NULL, threadfunc, NULL) != EOK)

   perror("thread create"), exit(EXIT_FAILURE);

 pthread_barrier_wait(&bfinish);

}

Перейти на страницу:

Похожие книги

1С: Бухгалтерия 8 с нуля
1С: Бухгалтерия 8 с нуля

Книга содержит полное описание приемов и методов работы с программой 1С:Бухгалтерия 8. Рассматривается автоматизация всех основных участков бухгалтерии: учет наличных и безналичных денежных средств, основных средств и НМА, прихода и расхода товарно-материальных ценностей, зарплаты, производства. Описано, как вводить исходные данные, заполнять справочники и каталоги, работать с первичными документами, проводить их по учету, формировать разнообразные отчеты, выводить данные на печать, настраивать программу и использовать ее сервисные функции. Каждый урок содержит подробное описание рассматриваемой темы с детальным разбором и иллюстрированием всех этапов.Для широкого круга пользователей.

Алексей Анатольевич Гладкий

Программирование, программы, базы данных / Программное обеспечение / Бухучет и аудит / Финансы и бизнес / Книги по IT / Словари и Энциклопедии
1С: Управление торговлей 8.2
1С: Управление торговлей 8.2

Современные торговые предприятия предлагают своим клиентам широчайший ассортимент товаров, который исчисляется тысячами и десятками тысяч наименований. Причем многие позиции могут реализовываться на разных условиях: предоплата, отсрочка платежи, скидка, наценка, объем партии, и т.д. Клиенты зачастую делятся на категории – VIP-клиент, обычный клиент, постоянный клиент, мелкооптовый клиент, и т.д. Товарные позиции могут комплектоваться и разукомплектовываться, многие товары подлежат обязательной сертификации и гигиеническим исследованиям, некондиционные позиции необходимо списывать, на складах периодически должна проводиться инвентаризация, каждая компания должна иметь свою маркетинговую политику и т.д., вообщем – современное торговое предприятие представляет живой организм, находящийся в постоянном движении.Очевидно, что вся эта кипучая деятельность требует автоматизации. Для решения этой задачи существуют специальные программные средства, и в этой книге мы познакомим вам с самым популярным продуктом, предназначенным для автоматизации деятельности торгового предприятия – «1С Управление торговлей», которое реализовано на новейшей технологической платформе версии 1С 8.2.

Алексей Анатольевич Гладкий

Финансы / Программирование, программы, базы данных