Читаем Linux API. Исчерпывающее руководство полностью

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



Рис. 30.2.Использование мьютекса для защиты критического участка


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


30.1.1. Статически выделяемые мьютексы

Мьютекс должен быть выделен в виде статической переменной или создан динамически во время выполнения программы (например, в блоке памяти выделенном с помощью вызова malloc()). Динамическое создание мьютексов является несколько более сложным, поэтому мы отложим его обсуждение до подраздела 30.1.5.

Мьютекс представляет собой переменную типа pthread_mutex_t. Прежде чем вы сможете его использовать, он должен быть инициализирован. В случае со статически выделенным мьютексом это можно сделать путем присваивания ему значения PTHREAD_MUTEX_INITIALIZER, как показано ниже:

pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;

Согласно стандарту SUSv3 применение операций, которые будут описаны в оставшейся части этого раздела, к копии мьютекса приводит к неопределенным результатам. Эти операции всегда должны выполняться с оригиналом мьютекса, инициализированным статически, с помощью значения PTHREAD_MUTEX_INITIALIZER, или динамически, путем вызова pthread_mutex_init() (описанного в разделе 30.1.5).


30.1.2. Закрытие и открытие мьютекса

После инициализации мьютекс находится в открытом состоянии. Для его закрытия и открытия используются функции pthread_mutex_lock() и pthread_mutex_unlock().

#include


int pthread_mutex_lock(pthread_mutex_t *mutex);

int pthread_mutex_unlock(pthread_mutex_t *mutex);

Обе возвращают 0 при успешном завершении или положительное число, если случилась ошибка

Чтобы закрыть мьютекс, его нужно передать в вызов pthread_mutex_lock(). Если он в данный момент открыт, вызов сразу же возвращается. Если же мьютекс закрыт другим потоком, pthread_mutex_lock() блокируется, пока тот не откроется; в момент открытия данная функция снова блокирует мьютекс и возвращается.

Если вызывающий поток сам закрыл мьютекс, переданный в функцию pthread_mutex_lock(), тогда, если это стандартный тип мьютекса, тогда случится одно из двух, в зависимости от реализации: либо поток войдет в состояние взаимного блокирования, пытаясь закрыть мьютекс, которым он уже владеет, либо вызов завершится неудачей и вернет ошибку EDEADLK. В Linux по умолчанию происходит взаимное блокирование (другие возможные варианты будут описаны после рассмотрения разных типов мьютексов в подразделе 30.1.7).

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

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


Пример программы

Ниже представлена измененная версия листинга 30.1, которая использует мьютекс для защиты доступа к глобальной переменной glob. Запустив эту программу с тем же аргументом командной строки, что и раньше, мы увидим, что инкрементация значения glob всегда происходит предсказуемо:

$ ./thread_incr_mutex 10000000

glob = 20000000


Листинг 30.2. Использование мьютекса для защиты доступа к глобальной переменной

threads/thread_incr_mutex.c

#include

#include "tlpi_hdr.h"


static int glob = 0;

static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;


static void * /* 'arg' раз инкрементируем 'glob' */

threadFunc(void *arg)

{

int loops = *((int *) arg);

int loc, j, s;


for (j = 0; j < loops; j++) {

s = pthread_mutex_lock(&mtx);

if (s!= 0)

errExitEN(s, "pthread_mutex_lock");

loc = glob;

loc++;

glob = loc;


s = pthread_mutex_unlock(&mtx);

if (s!= 0)

errExitEN(s, "pthread_mutex_unlock");

}


return NULL;

}


int

main(int argc, char *argv[])

{

pthread_t t1, t2;

int loops, s;


loops = (argc > 1)? getInt(argv[1], GN_GT_0, "num-loops"): 10000000;


s = pthread_create(&t1, NULL, threadFunc, &loops);

if (s!= 0)

errExitEN(s, "pthread_create");

s = pthread_create(&t2, NULL, threadFunc, &loops);

if (s!= 0)

errExitEN(s, "pthread_create");

s = pthread_join(t1, NULL);

if (s!= 0)

errExitEN(s, "pthread_join");

s = pthread_join(t2, NULL);

if (s!= 0)

errExitEN(s, "pthread_join");


printf("glob = %d\n", glob);

exit(EXIT_SUCCESS);

}

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

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

C++ Primer Plus
C++ Primer Plus

C++ Primer Plus is a carefully crafted, complete tutorial on one of the most significant and widely used programming languages today. An accessible and easy-to-use self-study guide, this book is appropriate for both serious students of programming as well as developers already proficient in other languages.The sixth edition of C++ Primer Plus has been updated and expanded to cover the latest developments in C++, including a detailed look at the new C++11 standard.Author and educator Stephen Prata has created an introduction to C++ that is instructive, clear, and insightful. Fundamental programming concepts are explained along with details of the C++ language. Many short, practical examples illustrate just one or two concepts at a time, encouraging readers to master new topics by immediately putting them to use.Review questions and programming exercises at the end of each chapter help readers zero in on the most critical information and digest the most difficult concepts.In C++ Primer Plus, you'll find depth, breadth, and a variety of teaching techniques and tools to enhance your learning:• A new detailed chapter on the changes and additional capabilities introduced in the C++11 standard• Complete, integrated discussion of both basic C language and additional C++ features• Clear guidance about when and why to use a feature• Hands-on learning with concise and simple examples that develop your understanding a concept or two at a time• Hundreds of practical sample programs• Review questions and programming exercises at the end of each chapter to test your understanding• Coverage of generic C++ gives you the greatest possible flexibility• Teaches the ISO standard, including discussions of templates, the Standard Template Library, the string class, exceptions, RTTI, and namespaces

Стивен Прата

Программирование, программы, базы данных
1С: Бухгалтерия 8 с нуля
1С: Бухгалтерия 8 с нуля

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

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

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

В этом полном руководстве по C# 4.0 - языку программирования, разработанному специально для среды .NET, - детально рассмотрены все основные средства языка: типы данных, операторы, управляющие операторы, классы, интерфейсы, методы, делегаты, индексаторы, события, указатели, обобщения, коллекции, основные библиотеки классов, средства многопоточного программирования и директивы препроцессора. Подробно описаны новые возможности C#, в том числе PLINQ, библиотека TPL, динамический тип данных, а также именованные и необязательные аргументы. Это справочное пособие снабжено массой полезных советов авторитетного автора и сотнями примеров программ с комментариями, благодаря которым они становятся понятными любому читателю независимо от уровня его подготовки. Книга рассчитана на широкий круг читателей, интересующихся программированием на C#.Введите сюда краткую аннотацию

Герберт Шилдт

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