Синхронизация с семафори

Синхронизация с семафори

В четвъртото издание на популярния ръководството са основите на програмирането в операционната система Linux. Отчетено използване C / C ++ библиотека и инструменти за развитие стан-дарт организация система повикване, файл I / O, процесите на взаимодействие, програмирането на черупката средства, създаване на графични потребителски интерфейси с GTK на инструменти + или QT интервала, използването на контакти и т.н., описани компилация. програми, свързването им в библиотеките и работа с терминала I / O. Има техники за приложения за писане в среди GNOME® и KDE®, за съхранение на данни с използване на бази данни MySQL® и отстраняване на грешки програми. Книгата е добре структурирана, което прави ученето лесно и бързо.

За начинаещите Linux-програмисти

Книга: Linux програмиране Основи

Синхронизация с семафори

Раздели на тази страница:

Синхронизация с семафори

За семафор има две групи от интерфейсни функции: едната е взета от POSIX Realtime Разширения (POSIX Доплащане за реално време) и се прилагат към потока, а другият, известен като семафори, System V, обикновено се използва за синхронизиране на процесите. (Ще обсъдим втори тип в глава 14.) И двете групи не гарантират оперативната съвместимост и въпреки че много подобна, използващи подканващи различни функции.

Дейкстра, холандски компютърен специалист, компютърни науки, формулиран за пръв път идеята за семафори. Semaphore - това е специален вид променлива, която може да се промени с положителен или отрицателен прираст, но позоваването на променливата в най-важния момент е винаги с атомна дори в многонишковите програми. Това означава, че ако две теми (или повече) в програмата, които се опитват да променят стойността на семафора, системата гарантира, че всички операции, в действителност ще се извършват една след друга. В случай на нормални променливи поради наличието на противоречиви операции на различни потоци в една програма е произволна.

В този раздел, ние считаме, най-простият тип семафор, двоичен или двоичен семафор, че отнема само стойностите 0 и 1. Налице е по-обобщен вид на семафор, като се има предвид (преброяване) семафор приемане на по-широк диапазон от стойности. Обикновено, семафори, използвани за защита на софтуер програмка, така че само една част от изпълнение може да го промените по всяко време. Това изисква двоичен семафор. Понякога трябва да се даде възможност на ограничен брой потоци за извършване на дадена част от код, за да направите това, трябва да използвате броене семафор. Тъй като семафор на броене е много по-малко популярен, ние няма да ги обсъдим по-нататък, като каза само, че те са логично продължение на двоичен семафор и че действителните извиквания на функции трябва да са еднакви.

Имената на семафор функции не започват с pthread_ префикс. повечето от функциите, свързани с потока, и с sem_. четирите основни функции на семафора, използвани за стрийминг. Всички те са много прости.

Semaphore е създадена от sem_init функция. е обявена по следния начин.

#include
Int sem_init (sem_t * SEM, Int pshared, неподписан Int стойност);

Тази функция инициализира обекта, семафор, посочи от сем. тя определя възможността за споделяне (която ще обсъдим в минута) и задава основната стойност на цяло число. Pshared параметър контролира вида на семафор. Ако pshared е 0, семафор е местно, така и на текущия процес. В противен случай, семафор може да се споделя от различни процеси. В момента сме заинтересовани от семафори, които не се споделят между процеси. По време на писането на книга Linux операционна система не поддържа такова споделяне и прехвърляне на нула без стойностно изражение pshared води до срив на повикване.

На следващата двойка функции и контрол на семафор стойност се декларира по следния начин.

И двамата предприемат указател към обект, семафор се инициализира като се обадите sem_init.

Функция sem_post атомично увеличава стойността на семафора от 1. атомично в този случай означава, че ако две теми, като в същото време се опитват да се увеличи стойността на един семафор към 1, те не си пречат взаимно, както е в случая с двете програми, които четат и записват увеличението на стойността на файла в в същото време. Ако и двете програми се опитват да се увеличи стойността от 1, семафор винаги да бъде правилно да се увеличи стойността на 2.

Функция sem_wait атомично намалява стойността на семафор по един, но винаги изчаква, докато семафор до първия брояч не получава стойност различна от нула. По този начин, ако се обадите sem_wait семафор на стойност 2, потокът ще продължи да изпълнява и семафор ще бъде намален до 1. Ако sem_wait нарича семафор със стойност 0, функцията ще изчака до тогава, докато някой друг конец няма да се увеличи стойността, и тя ще бъде различна от нула. Ако и двете теми, които чакат в sem_wait функция. до същия семафор става различна от нула, и то се увеличава, когато една трета поток, само една от нишките, чакащи да бъде в състояние да намали семафора и да продължи; друга тема и така ще си остане чака. Тази способност на атомна "тест и комплект" в една функция и прави семафор толкова ценно.

забележка

Има и друга особеност на семафор sem_trywait - той се без блокиране на партньор sem_wait. Ние няма да го обсъдим в една книга и в бъдеще, повече информация вижте. В справочните страници.

Последната функция на семафор - sem_destroy. Тя прочиства семафор, когато сте готови с нея, и се обявява, както следва:

Отново, тази функция се указател към семафора и почиства всякакви ресурси, които може да бъде. Ако се опитате да унищожи семафор, която е в очакване на поток, ще получите съобщение за грешка.

Подобно на повечето други функции, като всички тези функции се върне 0 за успех.

Сега направете упражнението 12.3.

Упражнение 12.3. семафор поток

Thread3.c текст на тази програма се основава и на програмата за текст thread1.c. Тъй като те са значителни, ще представи нова версия напълно.

#include
#include
#include
#include
#include
#include
нищожен * thread_function (нищожен * арг);
sem_t bin_sem;
#define WORK_SIZE 1024
овъгляване work_area [WORK_SIZE];
INT основни () INT ВЕИ;
pthread_t a_thread;
невалидни * резултат нишка;
ВЕИ = sem_init (bin_sem, 0, 0);
ако perror ( "Semaphore започна неуспешно") (ВЕИ = 0!);
изход (EXIT_FAILURE);
>
ВЕИ = pthread_create (a_thread, NULL, thread_function, NULL);
ако (! ВЕИ = 0) perror ( "създаване Тема провали");
изход (EXIT_FAILURE);
>
ФОРМАТ ( "Input някакъв текст Enter" край ", за да finishn.");
докато (strncmp ( "край", work_area, 3) = 0!) fgets (work_area, WORK_SIZE, стандартния вход);
sem_post (bin_sem);
>
ФОРМАТ ( "nWaiting за нишка да завърши п.");
ВЕИ = pthread_join (a_thread, thread_result);
ако (ВЕИ = 0!) perror ( "Тема присъединят провали");
изход (EXIT_FAILURE);
>
ФОРМАТ ( "Тема joinedn");
sem_destroy (bin_sem);
изход (EXIT_SUCCESS);
>
невалидни * функция резба (невалидни * Arg) докато (! strncmp ( "край", работен кът, 3) = 0) ФОРМАТ ( "Вие вход charactersn.", strlen (work_area) -1);
sem_wait (bin_sem);
>
pthread_exit (NULL);
>

Първата важна промяна - включването semaphore.h файл, за да се осигури достъп до функциите на семафора. На следващо място, вие декларирате, семафор и няколко променливи и инициализира семафора, преди да създадете нова тема.

sem_t bin_sem;
#define WORK_SIZE 1024
овъгляване work_area [WORK_SIZE];
INT основни () INT ВЕИ;
pthread_t a_thread;
нищожен * thread_result;
ВЕИ = sem_init (bin_sem, 0, 0);
ако perror ( "Semaphore започна неуспешно") (ВЕИ = 0!);
изход (EXIT_FAILURE);
>

Имайте предвид, че първоначалната стойност на семафора е 0.

В основната функция. след като започнете нова тема, можете да прочетете някакъв текст от клавиатурата, качване на вашето работно място, а след това изграждане на семафор тезгяха използване sem_post:

ФОРМАТ ( "Input някакъв текст Enter" край ", за да finishn.");
докато (strncmp ( "край", work_area, 3) = 0!) fgets (work_area, WORK_SIZE, стандартния вход);
sem_post (bin_sem);
>

Новият нишката чакате семафор и след това се брои въвежданите символи:

sem_wait (bin_sem);
докато (! strncmp ( "край", work_area, 3) = 0) ФОРМАТ ( ". Може вход charactersn", strlen (work_area) -1);
sem_wait (bin_sem);
>

До семафор е настроено, вие чакате вход клавиатура. Когато получите някои вход, той освобождава семафора, което позволява на втората нишка да брои героите преди първата нишка започва четене вход от клавиатурата отново.

Отново, конци имат един и същ масив work_area. За кодът е по-кратко и е по-лесно да се следват, ние отново пропусна някои проверки за грешки, например, стойността се върна от sem_wait на функция. Но в кода на работната програма, винаги трябва да се провери върнатите стойности на грешка, ако няма достатъчна причина да не проверява.

Оставете програмата да работи:

$ Як -D_REENTRANT thread3.s -o теми -lpthread
$ ./thread3
Input някакъв текст. Enter "край", за да завършите
The Wasp Factory
Можете вход от 16 символа
Иън Банкс
Можете вход от 10 символа
край
В очакване на конци, за да приключите.
Тема присъедини

В поток програма грешки времето винаги са трудни за намиране, но програмата изглежда да бъдат адаптирани и входни бързо текст, и по-спокойни паузи.

Когато се инициализира семафор, тогава ще го попитам на първоначалната стойност на 0. Ето защо, когато започва потока, sem_wait кол отменя изпълнението и изчаква докато семафор става нула.

В основния поток чакате толкова дълго, докато вие няма да имате някакъв текст, а след това да увеличи стойноста на семафор тезгяха използване sem_post функция. което веднага дава друга тема да се върнат от функцията му sem_wait и започне да се изпълнява. След като преброи героите преминават отново предизвиква sem_wait и отменя изпълнението, докато основната нишка sem_post отново призовава за увеличаване на семафора.

Non-очевидните дефекти в развитието на тази цел, в резултат на скритите грешки, трудно да се изпусне. Нека малко да променя програмата thread3a.c, така че приносът на текст с клавиатурата бъде временно заменен автоматично генериран текст. Замяна на цикъла четене в главната, както следва:

ФОРМАТ ( "Input някакъв текст Enter" край ", за да finishn.");
докато (strncmp ( "край", work_area, 3) = 0!) ако (strncmp (work_area "бързо", 4) == 0) sem_post (bin_sem);
strcpy (work_area "Wheeee.");
> Иначе fgets (work_area, WORK_SIZE, стандартния вход);
>
sem_post (bin_sem);
>

Сега, ако влезе бързо. Програмата ще даде възможност на sem_post. да започне броенето характер, но веднага се актуализира work_area нещо друго.

$ Як -D_REENTRANT thread3a.s -o thread3a -lpthread
$ ./thread3a
Input някакъв текст. Enter "край", за да завършите
превишение
Вие входни 9 символа
FAST
Вие входни 7 знака
Вие входни 7 знака
Вие входни 7 знака
край
В очакване на конци, за да приключите.
Тема присъедини

Проблемът с тази програма е, че се очаква, че въвеждането на текст от програмата ще продължи толкова дълго, че друга нишка достатъчно време, за да се брои знаците преди основната нишка, за да го изпрати да се подготви нова част от текста, за да бъдат преброени. Когато се опитах да му предложи две групи от думи, за да се брои, бързо след помежду си (FAST от клавиатурата и след това Wheeee. Сформирана автоматично), вторият поток не са имали време да се изпълни. Но да се увеличи семафора няколко пъти, така че аз мисля, че потокът продължава да брои думи и намалява стойността на семафора, стига да не става нула отново.

Този пример показва как внимателни трябва да бъдете по-време? Е условия в многонишковите програми. Корекция на програмата може да се използва допълнителен семафор да получите най-главният поток да изчака, докато счита поток е имал възможност да завърша броя си, но тя е много по-лесно да се използва мутекс или изключителен семафор, които ще разгледаме по-долу.