logo

БАГАТОПОТОЧНІСТЬ У C

вступ:

У C термін 'багатопотоковість' описує використання численних нитки одночасно. Кожен потік виконує a інше завдання . Завдяки одночасному характеру багатопоточності багато завдань можуть виконуватися одночасно. Крім того, багатопотоковість зменшує Використання ресурсів ЦП . Є дві категорії багатозадачності: на основі процесу і на основі потоків . Коли щось описується як багатопотоковість, це означає, що принаймні два або, можливо, більше потоків виконуються в одному процесі одночасно. Ми повинні спочатку зрозуміти, що таке потік і процес, щоб зрозуміти багатопотоковість у C. Давайте розглянемо ці теми, щоб краще зрозуміти.

supw

Що таке процеси та потоки?

А нитка є фундаментальна споруда блокувати виконання будь-якого процесу. Програма складається з кількох процесів, і кожен процес складається з потоків, які є набагато більш базовими одиницями. Таким чином, потік можна вважати основним будівельним блоком процесу або більш простою одиницею, яка спільно визначає використання ЦП.

Наступні елементи включені в потік:

ID потоку:

Це особливе ID потоку який генерується під час формування потоку та зберігається протягом певного часу потоку.

Лічильник програми:

Це цінність, яку апаратні навантаження .

Зареєстрований набір:

Це колекція загальні реєстри .

Стек:

Це залишок того конкретна нитка .

Крім того, якщо два потоки працюють одночасно в одному процесі, вони спільно використовуються код , розділи даних та інші ресурси операційної системи, наприклад файл відкривається і сигнали . Важкий процес, тип звичайного процесу, може керувати одним потоком. Однак багатопотоковий контроль має здатність відкривати та виконувати кілька завдань одночасно. Завдяки використанню потоків система стає значно ефективнішою, тому вони корисні.

Відмінність між неодружений і багатопотоковість в C пояснюється. Перш за все, це а однопотоковий процес . В результаті весь блок-в т.ч код, дані, і т. д. - розглядається як один процес, і цей процес має лише один потік. Це означає, що ця техніка виконуватиме лише одне завдання за раз. Але є багатопоточний процес що стоїть проти цього. Є такі види діяльності код, стек, дані , і файли також, але вони виконуються кількома потоками, кожен з яких має власний стек і регістри. Враховуючи те, що в цій ситуації можна одночасно виконати багато завдань, процес відомий як a багатопоточний процес .

Нитка буває двох видів:

Тема на рівні користувача:

Це на рівні користувача, як випливає з назви. Ядро не має доступу до своїх даних.

Потік на рівні ядра

Тип потоку відноситься до зв'язку потоку з ядром і операційною системою системи.

процес- Ряд кроків, зроблених для виконання програми, можна назвати процес . Програма не виконується відразу після її запуску. Він розбитий на кілька основних кроків, які виконуються послідовно в організованому порядку, щоб зрештою привести до виконання процесу.

Процес, який було розбито на більш дрібні етапи, називається a «клон або дочірній процес», тоді як початковий процес називається «батьківський» процес . У пам’яті кожен процес використовує певний простір, який не використовується спільно з іншими процесами.

Процедура проходить кілька етапів перед виконанням.

НОВИЙ-

У цій ситуації відбувається новий процес створений .

ГОТОВИЙ-

Коли процес підготовлений і очікує на призначення процесора, він знаходиться в цьому стані.

зразок javascript

БІГ-

Коли процес активний, це стан.

ЧЕКАЮ-

Коли процес знаходиться в такому стані, щось є очікування статися.

ПРИПИНЕНО-

Це стан, у якому виконується процедура.

Чому C є багатопоточним?

Багатопотоковість в C ідею можна використовувати через паралелізм для покращення an функціональність програми . Розглянемо випадок, коли у вікні браузера відкрито кілька вкладок. Потім кожна вкладка працює одночасно і може згадуватися як a Нитка . Припускаючи, що ми використовуємо Microsoft Excel , обійдеться один потік форматування тексту , і одна нитка буде обробка введення . Таким чином, багатопотокова функція C дозволяє легко виконувати кілька завдань одночасно. Створення потоку відбувається значно швидше. Передача контексту між потоками відбувається швидше. Крім того, зв’язок між потоками може здійснюватися швидше, а завершення потоку є простим.

Як писати програми на С для багатопоточності?

Хоча багатопотокові програми не вбудовані в мову C, це можливо залежно від операційної системи. The Стандартна бібліотека threads.h використовується для реалізації ідеї багатопоточності в C . Однак на даний момент немає компілятора, який міг би це зробити. Ми повинні використовувати специфічні для платформи реалізації, такі як 'POSIX' бібліотеку потоків, використовуючи файл заголовка pthread.h , якщо ми хочемо використовувати багатопотоковість у C. 'Pthreads' інша назва цього. А POSIX нитку можна створити такими способами:

 #include pthread_create (thread, attr, start_routine, arg) 

В цьому випадку, Pthread_create створює новий потік, щоб зробити потік виконуваним. Це дозволяє реалізувати багатопотоковість у C скільки завгодно разів у вашому коді. Тут наведено параметри та їхні попередні описи.

нитка:

Це одинична ідентифікація що підпроцес повертає .

attr:

Коли ми хочемо встановити атрибути потоку, ми використовуємо це непрозорий атрибут .

перевести рядок як int java

start_routine:

Коли start_routine генерується, потік буде виконувати процедуру.

аргумент:

Параметр, який start_routine отримує. НУЛЬ буде використано, якщо аргументи не надано.

Деякі приклади багатопоточності C

Ось кілька прикладів проблем багатопоточності в C.

1. Проблема читача-письменника

Поширеною проблемою операційної системи з синхронізацією процесів є проблема читача/запису . Припустімо, що у нас є база даних Читачі і Письменники , дві різні категорії користувачів, мають доступ. Читачі це єдині, хто може читати бази даних, тоді як Письменники є єдиними, хто може читати базу даних і також оновлювати її. Давайте використовувати IRCTC як простий приклад. Якщо ми хочемо перевірити статус конкретного номер поїзда , просто введіть номер поїзда в систему, щоб переглянути відповідну інформацію про поїзд. Тут відображається лише та інформація, яка є на сайті. Оператор читання такий. Однак, якщо ми хочемо зарезервувати квиток, ми повинні заповнити форму бронювання квитків із такими деталями, як наше ім’я, вік тощо. Отже, ми виконаємо тут операцію запису. Будуть внесені деякі корективи База даних IRCTC .

Справа в тому, що кілька людей одночасно намагаються отримати доступ до База даних IRCTC . Вони можуть бути a письменник або a читач . Проблема виникає, якщо читач уже використовує базу даних, а запис одночасно отримує до неї доступ для роботи з тими самими даними. Інша проблема виникає, коли автор використовує базу даних, а читач отримує доступ до тієї самої інформації, що й у базі даних. По-третє, виникає складність, коли один автор оновлює базу даних, а інший намагається оновити дані в тій самій базі даних. Четвертий сценарій відбувається, коли два читачі намагаються отримати той самий матеріал. Усі ці проблеми виникають, якщо читач і запис використовують однакові дані бази даних.

Семафор - це метод, який використовується для вирішення цієї проблеми. Давайте розглянемо ілюстрацію того, як використовувати цю проблему.

Процес читання:

 #include #include #include int rc = 0; // Reader count int data = 0; // Shared data pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_twrt = PTHREAD_COND_INITIALIZER; void* reader(void* arg) { int reader_id = *(int*)arg; pthread_mutex_lock(&mutex); rc++; if (rc == 1) pthread_cond_wait(&wrt, &mutex); pthread_mutex_unlock(&mutex); // Reading the shared data printf('Reader %d reads data: %d
&apos;, reader_id, data); pthread_mutex_lock(&amp;mutex); rc--; if (rc == 0) pthread_cond_signal(&amp;wrt); pthread_mutex_unlock(&amp;mutex); return NULL; } int main() { pthread_treaders[5]; // Assuming 5 reader threads int reader_ids[5]; for (int i = 0; i<5; i++) { reader_ids[i]="i" + 1; pthread_create(&readers[i], null, reader, &reader_ids[i]); } joining reader threads for (int i="0;" i< 5; pthread_join(readers[i], null); return 0; < pre> <p> <strong>Output:</strong> </p> <pre> Reader 1 reads data: 0 Reader 2 reads data: 0 Reader 3 reads data: 0 Reader 4 reads data: 0 Reader 5 reads data: 0 </pre> <p> <strong>Explanation:</strong> </p> <p>In this code, we have the shared variable data and the <strong> <em>reader count rc</em> </strong> . The <strong> <em>wrt condition</em> </strong> variable is used to limit access for the <strong> <em>writer process</em> </strong> , and the <strong> <em>mutex</em> </strong> is used to guarantee mutual exclusion for accessing the shared data.</p> <p>The reader process is represented by the <strong> <em>reader() function</em> </strong> . The <strong> <em>reader count (rc)</em> </strong> is increased before attaining the <strong> <em>mutex lock</em> </strong> . It uses <strong> <em>pthread_cond_wait()</em> </strong> to wait on the <strong> <em>wrt condition</em> </strong> variable if it is the <strong> <em>first reader (rc == 1)</em> </strong> . As a result, writers will be prevented from writing until all readers have completed.</p> <p>The reader process checks if it was the <strong> <em>last reader (rc == 0)</em> </strong> and lowers the reader <strong> <em>count (rc--)</em> </strong> after reading the shared data. If it was, <strong> <em>pthread_cond_signal()</em> </strong> signals the <strong> <em>wrt condition</em> </strong> variable to let waiting writer processes continue.</p> <p>Using the <strong> <em>pthread_create()</em> </strong> and <strong> <em>pthread_join() functions</em> </strong> , we <strong> <em>new</em> </strong> and <strong> <em>join</em> </strong> multiple reader threads in the <strong> <em>main() function</em> </strong> . An individual ID is assigned to each reader thread for identifying purposes.</p> <h3>Writer process:</h3> <pre> wait(wrt); . . WRITE INTO THE OBJECT . signal(wrt); </pre> <p>In the above example, same as the <strong> <em>reader process</em> </strong> , an operation known as the wait operation is carried out on <strong> <em>&apos;wrt&apos;</em> </strong> when a user wishes to access the data or object. After that, the new user won&apos;t be able to access the object. And once the user has finished writing, another signal operation is performed on <strong> <em>wrt</em> </strong> .</p> <h3>2. lock and unlock problem:</h3> <p>The idea of a <strong> <em>mutex</em> </strong> is utilized in multithreading in C to guarantee that there won&apos;t be a <strong> <em>race condition</em> </strong> between the <strong> <em>threads</em> </strong> . When multiple threads begin processing the same data at once, this circumstance is known as <strong> <em>racing</em> </strong> . However, if these circumstances exist, we must. We use the <strong> <em>mutex&apos;s lock()</em> </strong> and <strong> <em>unlock() functions</em> </strong> to secure a particular section of code for a specific thread. Such that, another thread cannot begin performing the same operation. The <strong> <em>&apos;critical section/region&apos;</em> </strong> is the name given to this protected code area. Before using the shared resources, we set up a lot in a certain area, and once we&apos;ve finished using them, we unlock them once more.</p> <p>Let&apos;s examine the operation of the mutex for locking and unlocking in multithreading in C:</p> <p> <strong>Example:</strong> </p> <pre> #include #include #include pthread_mutex_tmy_mutex = PTHREAD_MUTEX_INITIALIZER; int shared_data = 0; void *thread_function(void *arg) { pthread_mutex_lock(&amp;my_mutex); shared_data++; // Modify the shared data printf(&apos;Thread %ld: Shared data modified. New value: %d
&apos;, (long)arg, shared_data); pthread_mutex_unlock(&amp;my_mutex); return NULL; } int main() { pthread_tthreads[5]; // Assuming 5 threads for (int i = 0; i<5; i++) { if (pthread_create(&threads[i], null, thread_function, (void *)(long)(i + 1)) !="0)" fprintf(stderr, 'error creating thread %d
', i 1); return 1; } for (int i< 5; (pthread_join(threads[i], null) joining 0; < pre> <p> <strong>Output:</strong> </p> <pre> Thread 1: Shared data modified. New value: 1 Thread 2: Shared data modified. New value: 2 Thread 3: Shared data modified. New value: 3 Thread 4: Shared data modified. New value: 4 Thread 5: Shared data modified. New value: 5 </pre> <p> <strong>Explanation:</strong> </p> <p>In this above example, we explain how we <strong> <em>lock</em> </strong> and <strong> <em>unlock</em> </strong> a certain region of code that shields us from the racing situation. <strong> <em>&apos;pthread_mutex_t&apos;</em> </strong> is used as an <strong> <em>initializer</em> </strong> in the example above. <strong> <em>&apos;pthread_mutex_lock&apos;</em> </strong> is then <strong> <em>written</em> </strong> before the beginning of the code that we want to lock. The coding that we wish to lock is finished after that. After that, the locking of the code is terminated using <strong> <em>&apos;pthread_mutex_unlock&apos;</em> </strong> ; going forward, no code will be in lock mode.</p> <h2>The Dining Philosopher Problem:</h2> <p>One of the classic issues with synchronization is the <strong> <em>dining philosopher issue</em> </strong> . Simple resource allocation for several processes is required but shouldn&apos;t result in a <strong> <em>stalemate</em> </strong> or <strong> <em>hunger</em> </strong> . The <strong> <em>dining philosopher problem</em> </strong> can be viewed as a straightforward representation of a number of processes, each of which is demanding resources. Since each of these processes requires a resource allocation, it is necessary to distribute those resources across all of the processes so that no one process ever gets stuck or stops working.</p> <p>Assume there are five philosophers seated at a <strong> <em>circle-shaped table</em> </strong> . They eat at one point and ponder about something at another. Around the round table, the philosophers are evenly spaced out on the chairs. Additionally, there is a bowl of rice and five chopsticks for each philosopher in the middle of the table. When the philosopher feels she cannot interact with her colleagues who are seated nearby.</p> <p>A philosopher occasionally takes up two chopsticks when she becomes hungry. She chooses two chopsticks from her neighbors-one on her <strong> <em>left</em> </strong> and one on her <strong> <em>right</em> </strong> -that are within easy reach. But the philosopher should never pick up more than one chopstick at once. She will obviously be unable to pick up the chopstick that the neighbor is using.</p> <p> <strong>Example:</strong> </p> <p>Let&apos;s use an example to demonstrate how this is implemented in C.</p> <pre> #include #include #include #include #include pthread_tphilosopher[5]; pthread_mutex_tchopstick[5]; void *func(void *arg) { int n = *(int *)arg; printf(&apos;
Philosopher %d is thinking.&apos;, n); pthread_mutex_lock(&amp;chopstick[n]); pthread_mutex_lock(&amp;chopstick[(n + 1) % 5]); printf(&apos;
Philosopher %d is eating.&apos;, n); sleep(3); pthread_mutex_unlock(&amp;chopstick[n]); pthread_mutex_unlock(&amp;chopstick[(n + 1) % 5]); printf(&apos;
Philosopher %d Finished eating &apos;, n); return NULL; } int main() { int i, k; void *message; for (i = 0; i<5; i++) { k="pthread_mutex_init(&amp;chopstick[i]," null); if (k !="0)" printf('failed to initialize the mutex
'); exit(1); } for (i="0;" i< 5; null, func, (void *)&i); printf('error in thread creation.
'); &message); join thread.
'); printf('mutex destroyed.
'); return 0; < pre> <p> <strong>Output:</strong> </p> <pre> Philosopher 0 is thinking. Philosopher 1 is thinking. Philosopher 2 is thinking. Philosopher 3 is thinking. Philosopher 4 is thinking. Philosopher 0 is eating. Philosopher 1 is eating. Philosopher 2 is eating. Philosopher 3 is eating. Philosopher 4 is eating. Philosopher 0 Finished eating Philosopher 1 Finished eating Philosopher 2 Finished eating Philosopher 3 Finished eating Philosopher 4 Finished eating </pre> <p> <strong>Explanation:</strong> </p> <p> <strong> <em>Chopsticks</em> </strong> can be represented by a semaphore. Since there are <strong> <em>chopsticks</em> </strong> on the table and no philosopher has chosen one, all of the chopsticks&apos; components are first initialized to <strong> <em>1</em> </strong> . Now that <strong> <em>chopstick[i]</em> </strong> has been chosen as the first <strong> <em>chopstick. chopstick[i]</em> </strong> and <strong> <em>chopstick[(i+1)%5]</em> </strong> are subject to the first wait operation. These <strong> <em>chopsticks&apos; wait operation</em> </strong> indicates that the philosopher has picked them up. The eating process begins once the philosopher selects his <strong> <em>chopstick</em> </strong> . The signal operation is now carried out on the <strong> <em>chopsticks [i]</em> </strong> and <strong> <em>[(i+1)%5]</em> </strong> once the philosopher has finished eating. The philosopher then turns back to sleep.</p> <p>To determine whether the <strong> <em>subthread</em> </strong> has joined the main thread or not, we used the <strong> <em>pthread_join function</em> </strong> . Similarly, we have checked whether the <strong> <em>mutex</em> </strong> lock has been initialized using the <strong> <em>pthread_mutex_init</em> </strong> method.</p> <p>To initialize and verify whether the new thread was created or not, we utilized the <strong> <em>pthread_create function</em> </strong> . Similar to this, we destroyed the <strong> <em>mutex lock</em> </strong> using the <strong> <em>pthread_mutex_destroy</em> </strong> function.</p> <h2>The Producer-Consumer Problem:</h2> <p>A common issue with multithreading process synchronization is the <strong> <em>producer-consumer problem</em> </strong> . Two processes are present in it: the first is the <strong> <em>producer&apos;s process</em> </strong> , and the second is the <strong> <em>consumer&apos;s process</em> </strong> . Furthermore, it is assumed that both operations are occurring concurrently in parallel. Additionally, they are a cooperative process, which implies that they are sharing something with one another. It is important that when the buffer is <strong> <em>full</em> </strong> , the producer cannot add data. When the buffer is empty, the consumer cannot extract data from the buffer because the common buffer size between the producer and the consumer is <strong> <em>fixed</em> </strong> . The issue is stated in this way. Hence, to implement the Producer-Consumer problem and solve it, we shall employ the idea of parallel programming.</p> <p> <strong>Example:</strong> </p> <pre> #include #include int mutex = 1, full = 0, empty = 3, x = 0; int main() { int n; void producer(); void consumer(); int wait(int); int signal(int); printf(&apos;
1.producer
2.consumer
3.for exit&apos;); while (1) { printf(&apos;
 Please enter your choice:&apos;); scanf(&apos;%d&apos;, &amp;n); switch (n) { case 1: if ((mutex == 1) &amp;&amp; (empty != 0)) producer(); else printf(&apos;Oops!! the buffer is full!!&apos;); break; case 2: if ((mutex == 1) &amp;&amp; (full != 0)) consumer(); else printf(&apos;Oops!! the buffer is empty!!&apos;); break; case 3: exit(0); break; } } return 0; } int wait(int s) { return (--s); } int signal(int s) { return (++s); } void producer() { mutex = wait(mutex); full = signal(full); empty = wait(empty); x++; printf(&apos;
Item produced by the Producer %d&apos;, x); mutex = signal(mutex); } void consumer() { mutex = wait(mutex); full = wait(full); empty = signal(empty); printf(&apos;
Item consumed by the Consumer %d&apos;, x); x--; mutex = signal(mutex); } </pre> <p> <strong>Output:</strong> </p> <pre> 1. producer 2. consumer 3. for exit Please enter your choice: </pre> <p> <strong>Explanation:</strong> </p> <p>We perform two tasks. The functions <strong> <em>consumer()</em> </strong> and <strong> <em>producer()</em> </strong> indicate the status and operation of the <strong> <em>consumer</em> </strong> and <strong> <em>producer</em> </strong> . The <strong> <em>producer() method</em> </strong> will create the <strong> <em>mutex lock</em> </strong> and determine whether the buffer is <strong> <em>full</em> </strong> when it is called. When the buffer is full, nothing will be produced. If not, it will <strong> <em>create</em> </strong> , and then, after the <strong> <em>production</em> </strong> , it will put itself to sleep to unlock the <strong> <em>mutex lock</em> </strong> . Like the <strong> <em>producer</em> </strong> , the consumer first creates the <strong> <em>mutex lock</em> </strong> , checks the <strong> <em>buffer</em> </strong> , consumes the <strong> <em>product</em> </strong> , and then releases the lock before going back to sleep.</p> <p>A <strong> <em>counter (x)</em> </strong> will be used during manufacturing and will keep growing until the manufacturer produces the item. However, the consumer will make fewer of the same manufactured <strong> <em>item (x)</em> </strong> .</p> <h2>Conclusion:</h2> <p>The idea of using <strong> <em>two</em> </strong> or <strong> <em>more threads</em> </strong> to execute a program is known as <strong> <em>multithreading</em> </strong> in the C programming language. <strong> <em>Multithreading</em> </strong> allows for the simultaneous execution of several tasks. The simplest executable component of a program is a <strong> <em>thread</em> </strong> . The process is the idea that a task can be completed by breaking it up into several smaller <strong> <em>sub-processes</em> </strong> .</p> <p>The header file <strong> <em>pthread.h</em> </strong> is required in order to implement multithreading in C since it cannot be done directly.</p> <hr></5;></pre></5;></pre></5;>

Пояснення:

У цьому коді ми маємо спільні дані змінної та кількість читачів rc . The відносно стану змінна використовується для обмеження доступу для процес письменника , і м'ютекс використовується для гарантування взаємного виключення доступу до спільних даних.

Читацький процес представлений функція reader(). . The кількість читачів (rc) збільшується до досягнення блокування м'ютексу . Це використовує pthread_cond_wait() чекати на відносно стану змінна, якщо це перший читач (rc == 1) . У результаті авторам буде заборонено писати, доки всі читачі не завершать.

Процес читання перевіряє, чи це було останній читач (rc == 0) і опускає читачку кількість (rc--) після прочитання спільних даних. Якби це було, pthread_cond_signal() сигналізує відносно стану змінна, яка дозволяє продовжувати процеси запису в очікуванні.

Використовуючи pthread_create() і функції pthread_join(). , ми новий і приєднатися кілька тем для читання в функція main(). . Індивідуальний ідентифікатор призначається кожному потоку зчитувача з метою ідентифікації.

Процес запису:

 wait(wrt); . . WRITE INTO THE OBJECT . signal(wrt); 

У наведеному вище прикладі так само, як процес читання , виконується операція, відома як операція очікування 'wrt' коли користувач бажає отримати доступ до даних або об’єкта. Після цього новий користувач не матиме доступу до об’єкта. Після того, як користувач закінчив запис, виконується інша операція сигналу wrt .

2. проблема блокування та розблокування:

Ідея а м'ютекс використовується в багатопоточності в C, щоб гарантувати, що не буде a стан гонки між нитки . Коли кілька потоків починають обробляти ті самі дані одночасно, ця обставина відома як перегони . Однак, якщо ці обставини існують, ми повинні. Ми використовуємо блокування м'ютексу() і функції unlock(). щоб захистити певний розділ коду для конкретного потоку. Таким чином, інший потік не може розпочати виконання тієї ж операції. The 'критична ділянка/регіон' це назва цієї захищеної області коду. Перш ніж використовувати спільні ресурси, ми налаштовуємо багато в певній області, а коли ми закінчили використовувати їх, ми їх знову розблоковуємо.

Давайте розглянемо роботу м'ютексу для блокування та розблокування в багатопоточності в C:

приклад:

 #include #include #include pthread_mutex_tmy_mutex = PTHREAD_MUTEX_INITIALIZER; int shared_data = 0; void *thread_function(void *arg) { pthread_mutex_lock(&amp;my_mutex); shared_data++; // Modify the shared data printf(&apos;Thread %ld: Shared data modified. New value: %d
&apos;, (long)arg, shared_data); pthread_mutex_unlock(&amp;my_mutex); return NULL; } int main() { pthread_tthreads[5]; // Assuming 5 threads for (int i = 0; i<5; i++) { if (pthread_create(&threads[i], null, thread_function, (void *)(long)(i + 1)) !="0)" fprintf(stderr, \'error creating thread %d
\', i 1); return 1; } for (int i< 5; (pthread_join(threads[i], null) joining 0; < pre> <p> <strong>Output:</strong> </p> <pre> Thread 1: Shared data modified. New value: 1 Thread 2: Shared data modified. New value: 2 Thread 3: Shared data modified. New value: 3 Thread 4: Shared data modified. New value: 4 Thread 5: Shared data modified. New value: 5 </pre> <p> <strong>Explanation:</strong> </p> <p>In this above example, we explain how we <strong> <em>lock</em> </strong> and <strong> <em>unlock</em> </strong> a certain region of code that shields us from the racing situation. <strong> <em>&apos;pthread_mutex_t&apos;</em> </strong> is used as an <strong> <em>initializer</em> </strong> in the example above. <strong> <em>&apos;pthread_mutex_lock&apos;</em> </strong> is then <strong> <em>written</em> </strong> before the beginning of the code that we want to lock. The coding that we wish to lock is finished after that. After that, the locking of the code is terminated using <strong> <em>&apos;pthread_mutex_unlock&apos;</em> </strong> ; going forward, no code will be in lock mode.</p> <h2>The Dining Philosopher Problem:</h2> <p>One of the classic issues with synchronization is the <strong> <em>dining philosopher issue</em> </strong> . Simple resource allocation for several processes is required but shouldn&apos;t result in a <strong> <em>stalemate</em> </strong> or <strong> <em>hunger</em> </strong> . The <strong> <em>dining philosopher problem</em> </strong> can be viewed as a straightforward representation of a number of processes, each of which is demanding resources. Since each of these processes requires a resource allocation, it is necessary to distribute those resources across all of the processes so that no one process ever gets stuck or stops working.</p> <p>Assume there are five philosophers seated at a <strong> <em>circle-shaped table</em> </strong> . They eat at one point and ponder about something at another. Around the round table, the philosophers are evenly spaced out on the chairs. Additionally, there is a bowl of rice and five chopsticks for each philosopher in the middle of the table. When the philosopher feels she cannot interact with her colleagues who are seated nearby.</p> <p>A philosopher occasionally takes up two chopsticks when she becomes hungry. She chooses two chopsticks from her neighbors-one on her <strong> <em>left</em> </strong> and one on her <strong> <em>right</em> </strong> -that are within easy reach. But the philosopher should never pick up more than one chopstick at once. She will obviously be unable to pick up the chopstick that the neighbor is using.</p> <p> <strong>Example:</strong> </p> <p>Let&apos;s use an example to demonstrate how this is implemented in C.</p> <pre> #include #include #include #include #include pthread_tphilosopher[5]; pthread_mutex_tchopstick[5]; void *func(void *arg) { int n = *(int *)arg; printf(&apos;
Philosopher %d is thinking.&apos;, n); pthread_mutex_lock(&amp;chopstick[n]); pthread_mutex_lock(&amp;chopstick[(n + 1) % 5]); printf(&apos;
Philosopher %d is eating.&apos;, n); sleep(3); pthread_mutex_unlock(&amp;chopstick[n]); pthread_mutex_unlock(&amp;chopstick[(n + 1) % 5]); printf(&apos;
Philosopher %d Finished eating &apos;, n); return NULL; } int main() { int i, k; void *message; for (i = 0; i<5; i++) { k="pthread_mutex_init(&amp;chopstick[i]," null); if (k !="0)" printf(\'failed to initialize the mutex
\'); exit(1); } for (i="0;" i< 5; null, func, (void *)&i); printf(\'error in thread creation.
\'); &message); join thread.
\'); printf(\'mutex destroyed.
\'); return 0; < pre> <p> <strong>Output:</strong> </p> <pre> Philosopher 0 is thinking. Philosopher 1 is thinking. Philosopher 2 is thinking. Philosopher 3 is thinking. Philosopher 4 is thinking. Philosopher 0 is eating. Philosopher 1 is eating. Philosopher 2 is eating. Philosopher 3 is eating. Philosopher 4 is eating. Philosopher 0 Finished eating Philosopher 1 Finished eating Philosopher 2 Finished eating Philosopher 3 Finished eating Philosopher 4 Finished eating </pre> <p> <strong>Explanation:</strong> </p> <p> <strong> <em>Chopsticks</em> </strong> can be represented by a semaphore. Since there are <strong> <em>chopsticks</em> </strong> on the table and no philosopher has chosen one, all of the chopsticks&apos; components are first initialized to <strong> <em>1</em> </strong> . Now that <strong> <em>chopstick[i]</em> </strong> has been chosen as the first <strong> <em>chopstick. chopstick[i]</em> </strong> and <strong> <em>chopstick[(i+1)%5]</em> </strong> are subject to the first wait operation. These <strong> <em>chopsticks&apos; wait operation</em> </strong> indicates that the philosopher has picked them up. The eating process begins once the philosopher selects his <strong> <em>chopstick</em> </strong> . The signal operation is now carried out on the <strong> <em>chopsticks [i]</em> </strong> and <strong> <em>[(i+1)%5]</em> </strong> once the philosopher has finished eating. The philosopher then turns back to sleep.</p> <p>To determine whether the <strong> <em>subthread</em> </strong> has joined the main thread or not, we used the <strong> <em>pthread_join function</em> </strong> . Similarly, we have checked whether the <strong> <em>mutex</em> </strong> lock has been initialized using the <strong> <em>pthread_mutex_init</em> </strong> method.</p> <p>To initialize and verify whether the new thread was created or not, we utilized the <strong> <em>pthread_create function</em> </strong> . Similar to this, we destroyed the <strong> <em>mutex lock</em> </strong> using the <strong> <em>pthread_mutex_destroy</em> </strong> function.</p> <h2>The Producer-Consumer Problem:</h2> <p>A common issue with multithreading process synchronization is the <strong> <em>producer-consumer problem</em> </strong> . Two processes are present in it: the first is the <strong> <em>producer&apos;s process</em> </strong> , and the second is the <strong> <em>consumer&apos;s process</em> </strong> . Furthermore, it is assumed that both operations are occurring concurrently in parallel. Additionally, they are a cooperative process, which implies that they are sharing something with one another. It is important that when the buffer is <strong> <em>full</em> </strong> , the producer cannot add data. When the buffer is empty, the consumer cannot extract data from the buffer because the common buffer size between the producer and the consumer is <strong> <em>fixed</em> </strong> . The issue is stated in this way. Hence, to implement the Producer-Consumer problem and solve it, we shall employ the idea of parallel programming.</p> <p> <strong>Example:</strong> </p> <pre> #include #include int mutex = 1, full = 0, empty = 3, x = 0; int main() { int n; void producer(); void consumer(); int wait(int); int signal(int); printf(&apos;
1.producer
2.consumer
3.for exit&apos;); while (1) { printf(&apos;
 Please enter your choice:&apos;); scanf(&apos;%d&apos;, &amp;n); switch (n) { case 1: if ((mutex == 1) &amp;&amp; (empty != 0)) producer(); else printf(&apos;Oops!! the buffer is full!!&apos;); break; case 2: if ((mutex == 1) &amp;&amp; (full != 0)) consumer(); else printf(&apos;Oops!! the buffer is empty!!&apos;); break; case 3: exit(0); break; } } return 0; } int wait(int s) { return (--s); } int signal(int s) { return (++s); } void producer() { mutex = wait(mutex); full = signal(full); empty = wait(empty); x++; printf(&apos;
Item produced by the Producer %d&apos;, x); mutex = signal(mutex); } void consumer() { mutex = wait(mutex); full = wait(full); empty = signal(empty); printf(&apos;
Item consumed by the Consumer %d&apos;, x); x--; mutex = signal(mutex); } </pre> <p> <strong>Output:</strong> </p> <pre> 1. producer 2. consumer 3. for exit Please enter your choice: </pre> <p> <strong>Explanation:</strong> </p> <p>We perform two tasks. The functions <strong> <em>consumer()</em> </strong> and <strong> <em>producer()</em> </strong> indicate the status and operation of the <strong> <em>consumer</em> </strong> and <strong> <em>producer</em> </strong> . The <strong> <em>producer() method</em> </strong> will create the <strong> <em>mutex lock</em> </strong> and determine whether the buffer is <strong> <em>full</em> </strong> when it is called. When the buffer is full, nothing will be produced. If not, it will <strong> <em>create</em> </strong> , and then, after the <strong> <em>production</em> </strong> , it will put itself to sleep to unlock the <strong> <em>mutex lock</em> </strong> . Like the <strong> <em>producer</em> </strong> , the consumer first creates the <strong> <em>mutex lock</em> </strong> , checks the <strong> <em>buffer</em> </strong> , consumes the <strong> <em>product</em> </strong> , and then releases the lock before going back to sleep.</p> <p>A <strong> <em>counter (x)</em> </strong> will be used during manufacturing and will keep growing until the manufacturer produces the item. However, the consumer will make fewer of the same manufactured <strong> <em>item (x)</em> </strong> .</p> <h2>Conclusion:</h2> <p>The idea of using <strong> <em>two</em> </strong> or <strong> <em>more threads</em> </strong> to execute a program is known as <strong> <em>multithreading</em> </strong> in the C programming language. <strong> <em>Multithreading</em> </strong> allows for the simultaneous execution of several tasks. The simplest executable component of a program is a <strong> <em>thread</em> </strong> . The process is the idea that a task can be completed by breaking it up into several smaller <strong> <em>sub-processes</em> </strong> .</p> <p>The header file <strong> <em>pthread.h</em> </strong> is required in order to implement multithreading in C since it cannot be done directly.</p> <hr></5;></pre></5;>

Пояснення:

pvr повна форма

У цьому вище прикладі ми пояснюємо, як ми замок і розблокувати певна область коду, яка захищає нас від перегонів. 'pthread_mutex_t' використовується як ініціалізатор у прикладі вище. 'pthread_mutex_lock' є тоді написаний перед початком коду, який ми хочемо заблокувати. Після цього кодування, яке ми хочемо заблокувати, буде завершено. Після цього блокування коду припиняється за допомогою 'pthread_mutex_unlock' ; надалі жоден код не буде в режимі блокування.

Проблема обіднього філософа:

Однією з класичних проблем із синхронізацією є обідній філософ питання . Потрібний простий розподіл ресурсів для кількох процесів, але це не повинно призводити до патова ситуація або голод . The обідня проблема філософа можна розглядати як пряме представлення ряду процесів, кожен з яких вимагає ресурсів. Оскільки кожен із цих процесів потребує розподілу ресурсів, необхідно розподілити ці ресурси між усіма процесами, щоб жоден процес ніколи не застряг або припинив роботу.

Припустимо, що п’ять філософів сидять за адресою стіл у формі кола . Вони в один момент їдять, а в інший про щось розмірковують. Навколо круглого столу рівномірно розташувалися на стільцях філософи. Крім того, посередині столу є миска з рисом і п’ять паличок для їжі для кожного філософа. Коли філософ відчуває, що не може спілкуватися з колегами, які сидять поруч.

Філософ час від часу бере до рук дві палички, коли відчуває голод. Вона вибирає у сусідів дві палички — одну на собі зліва і один на неї правильно - які знаходяться в межах легкої досяжності. Але філософ ніколи не повинен брати в руки більше однієї палички одночасно. Вона, очевидно, не зможе підняти паличку, якою користується сусід.

приклад:

рядки java

Давайте використаємо приклад, щоб продемонструвати, як це реалізовано в C.

 #include #include #include #include #include pthread_tphilosopher[5]; pthread_mutex_tchopstick[5]; void *func(void *arg) { int n = *(int *)arg; printf(&apos;
Philosopher %d is thinking.&apos;, n); pthread_mutex_lock(&amp;chopstick[n]); pthread_mutex_lock(&amp;chopstick[(n + 1) % 5]); printf(&apos;
Philosopher %d is eating.&apos;, n); sleep(3); pthread_mutex_unlock(&amp;chopstick[n]); pthread_mutex_unlock(&amp;chopstick[(n + 1) % 5]); printf(&apos;
Philosopher %d Finished eating &apos;, n); return NULL; } int main() { int i, k; void *message; for (i = 0; i<5; i++) { k="pthread_mutex_init(&amp;chopstick[i]," null); if (k !="0)" printf(\'failed to initialize the mutex
\'); exit(1); } for (i="0;" i< 5; null, func, (void *)&i); printf(\'error in thread creation.
\'); &message); join thread.
\'); printf(\'mutex destroyed.
\'); return 0; < pre> <p> <strong>Output:</strong> </p> <pre> Philosopher 0 is thinking. Philosopher 1 is thinking. Philosopher 2 is thinking. Philosopher 3 is thinking. Philosopher 4 is thinking. Philosopher 0 is eating. Philosopher 1 is eating. Philosopher 2 is eating. Philosopher 3 is eating. Philosopher 4 is eating. Philosopher 0 Finished eating Philosopher 1 Finished eating Philosopher 2 Finished eating Philosopher 3 Finished eating Philosopher 4 Finished eating </pre> <p> <strong>Explanation:</strong> </p> <p> <strong> <em>Chopsticks</em> </strong> can be represented by a semaphore. Since there are <strong> <em>chopsticks</em> </strong> on the table and no philosopher has chosen one, all of the chopsticks&apos; components are first initialized to <strong> <em>1</em> </strong> . Now that <strong> <em>chopstick[i]</em> </strong> has been chosen as the first <strong> <em>chopstick. chopstick[i]</em> </strong> and <strong> <em>chopstick[(i+1)%5]</em> </strong> are subject to the first wait operation. These <strong> <em>chopsticks&apos; wait operation</em> </strong> indicates that the philosopher has picked them up. The eating process begins once the philosopher selects his <strong> <em>chopstick</em> </strong> . The signal operation is now carried out on the <strong> <em>chopsticks [i]</em> </strong> and <strong> <em>[(i+1)%5]</em> </strong> once the philosopher has finished eating. The philosopher then turns back to sleep.</p> <p>To determine whether the <strong> <em>subthread</em> </strong> has joined the main thread or not, we used the <strong> <em>pthread_join function</em> </strong> . Similarly, we have checked whether the <strong> <em>mutex</em> </strong> lock has been initialized using the <strong> <em>pthread_mutex_init</em> </strong> method.</p> <p>To initialize and verify whether the new thread was created or not, we utilized the <strong> <em>pthread_create function</em> </strong> . Similar to this, we destroyed the <strong> <em>mutex lock</em> </strong> using the <strong> <em>pthread_mutex_destroy</em> </strong> function.</p> <h2>The Producer-Consumer Problem:</h2> <p>A common issue with multithreading process synchronization is the <strong> <em>producer-consumer problem</em> </strong> . Two processes are present in it: the first is the <strong> <em>producer&apos;s process</em> </strong> , and the second is the <strong> <em>consumer&apos;s process</em> </strong> . Furthermore, it is assumed that both operations are occurring concurrently in parallel. Additionally, they are a cooperative process, which implies that they are sharing something with one another. It is important that when the buffer is <strong> <em>full</em> </strong> , the producer cannot add data. When the buffer is empty, the consumer cannot extract data from the buffer because the common buffer size between the producer and the consumer is <strong> <em>fixed</em> </strong> . The issue is stated in this way. Hence, to implement the Producer-Consumer problem and solve it, we shall employ the idea of parallel programming.</p> <p> <strong>Example:</strong> </p> <pre> #include #include int mutex = 1, full = 0, empty = 3, x = 0; int main() { int n; void producer(); void consumer(); int wait(int); int signal(int); printf(&apos;
1.producer
2.consumer
3.for exit&apos;); while (1) { printf(&apos;
 Please enter your choice:&apos;); scanf(&apos;%d&apos;, &amp;n); switch (n) { case 1: if ((mutex == 1) &amp;&amp; (empty != 0)) producer(); else printf(&apos;Oops!! the buffer is full!!&apos;); break; case 2: if ((mutex == 1) &amp;&amp; (full != 0)) consumer(); else printf(&apos;Oops!! the buffer is empty!!&apos;); break; case 3: exit(0); break; } } return 0; } int wait(int s) { return (--s); } int signal(int s) { return (++s); } void producer() { mutex = wait(mutex); full = signal(full); empty = wait(empty); x++; printf(&apos;
Item produced by the Producer %d&apos;, x); mutex = signal(mutex); } void consumer() { mutex = wait(mutex); full = wait(full); empty = signal(empty); printf(&apos;
Item consumed by the Consumer %d&apos;, x); x--; mutex = signal(mutex); } </pre> <p> <strong>Output:</strong> </p> <pre> 1. producer 2. consumer 3. for exit Please enter your choice: </pre> <p> <strong>Explanation:</strong> </p> <p>We perform two tasks. The functions <strong> <em>consumer()</em> </strong> and <strong> <em>producer()</em> </strong> indicate the status and operation of the <strong> <em>consumer</em> </strong> and <strong> <em>producer</em> </strong> . The <strong> <em>producer() method</em> </strong> will create the <strong> <em>mutex lock</em> </strong> and determine whether the buffer is <strong> <em>full</em> </strong> when it is called. When the buffer is full, nothing will be produced. If not, it will <strong> <em>create</em> </strong> , and then, after the <strong> <em>production</em> </strong> , it will put itself to sleep to unlock the <strong> <em>mutex lock</em> </strong> . Like the <strong> <em>producer</em> </strong> , the consumer first creates the <strong> <em>mutex lock</em> </strong> , checks the <strong> <em>buffer</em> </strong> , consumes the <strong> <em>product</em> </strong> , and then releases the lock before going back to sleep.</p> <p>A <strong> <em>counter (x)</em> </strong> will be used during manufacturing and will keep growing until the manufacturer produces the item. However, the consumer will make fewer of the same manufactured <strong> <em>item (x)</em> </strong> .</p> <h2>Conclusion:</h2> <p>The idea of using <strong> <em>two</em> </strong> or <strong> <em>more threads</em> </strong> to execute a program is known as <strong> <em>multithreading</em> </strong> in the C programming language. <strong> <em>Multithreading</em> </strong> allows for the simultaneous execution of several tasks. The simplest executable component of a program is a <strong> <em>thread</em> </strong> . The process is the idea that a task can be completed by breaking it up into several smaller <strong> <em>sub-processes</em> </strong> .</p> <p>The header file <strong> <em>pthread.h</em> </strong> is required in order to implement multithreading in C since it cannot be done directly.</p> <hr></5;>

Пояснення:

палички для їжі може бути представлений семафором. Оскільки є палички для їжі на столі, і жоден філософ не вибрав жодного, усі компоненти паличок спочатку ініціалізуються на 1 . Тепер це палички для їжі[i] було обрано першим паличка для їжі. палички для їжі[i] і паличка для їжі[(i+1)%5] підлягають першій операції очікування. Ці операція очікування паличок вказує на те, що філософ їх підхопив. Процес прийому їжі починається, коли філософ вибирає свій паличка для їжі . Операція сигналу тепер виконується на палички для їжі [i] і [(i+1)%5] як тільки філософ закінчив їсти. Потім філософ повертається спати.

Щоб визначити, чи є підтема приєднався до основного потоку чи ні, ми використовували функція pthread_join . Так само ми перевірили, чи є м'ютекс блокування було ініціалізовано за допомогою pthread_mutex_init метод.

Щоб ініціалізувати та перевірити, чи створено новий потік чи ні, ми використали функція pthread_create . Подібно до цього ми знищили блокування м'ютексу використовуючи pthread_mutex_destroy функція.

Проблема виробник-споживач:

Поширеною проблемою синхронізації багатопотокового процесу є проблема виробник-споживач . У ньому присутні два процеси: перший — це процес виробника , а другий - це споживчий процес . Крім того, передбачається, що обидві операції відбуваються одночасно і паралельно. Крім того, вони є процесом співпраці, що означає, що вони діляться чимось один з одним. Важливо, що коли буфер є повний , виробник не може додати дані. Коли буфер порожній, споживач не може отримати дані з буфера, оскільки загальний розмір буфера між виробником і споживачем фіксований . Проблема поставлена ​​таким чином. Отже, щоб реалізувати проблему Виробник-Споживач і вирішити її, ми будемо використовувати ідею паралельного програмування.

приклад:

 #include #include int mutex = 1, full = 0, empty = 3, x = 0; int main() { int n; void producer(); void consumer(); int wait(int); int signal(int); printf(&apos;
1.producer
2.consumer
3.for exit&apos;); while (1) { printf(&apos;
 Please enter your choice:&apos;); scanf(&apos;%d&apos;, &amp;n); switch (n) { case 1: if ((mutex == 1) &amp;&amp; (empty != 0)) producer(); else printf(&apos;Oops!! the buffer is full!!&apos;); break; case 2: if ((mutex == 1) &amp;&amp; (full != 0)) consumer(); else printf(&apos;Oops!! the buffer is empty!!&apos;); break; case 3: exit(0); break; } } return 0; } int wait(int s) { return (--s); } int signal(int s) { return (++s); } void producer() { mutex = wait(mutex); full = signal(full); empty = wait(empty); x++; printf(&apos;
Item produced by the Producer %d&apos;, x); mutex = signal(mutex); } void consumer() { mutex = wait(mutex); full = wait(full); empty = signal(empty); printf(&apos;
Item consumed by the Consumer %d&apos;, x); x--; mutex = signal(mutex); } 

Вихід:

 1. producer 2. consumer 3. for exit Please enter your choice: 

Пояснення:

Виконуємо два завдання. Функції споживач() і виробник() вказують на стан і роботу споживач і продюсер . The метод producer(). створить блокування м'ютексу і визначити, чи є буфер повний коли його називають. Коли буфер заповнений, нічого не буде створено. Якщо ні, то буде створити , а потім, після виробництва , він переведе себе в режим сну, щоб розблокувати блокування м'ютексу . Як продюсер , споживач спочатку створює блокування м'ютексу , перевіряє буфер , споживає продукт , а потім знімає блокування перед тим, як повернутися до сну.

А лічильник (x) використовуватимуться під час виробництва та продовжуватимуть зростати, доки виробник не виготовить предмет. Однак споживач буде робити менше такого ж виробництва пункт (x) .

висновок:

Ідея використання два або більше потоків для виконання програми відомий як багатопотоковість на мові програмування C. Багатопотоковість дозволяє виконувати кілька завдань одночасно. Найпростішим виконуваним компонентом програми є a нитка . Процес — це ідея про те, що завдання можна виконати, розділивши його на кілька менших підпроцеси .

Заголовний файл pthread.h необхідний для реалізації багатопоточності в C, оскільки це неможливо зробити безпосередньо.