logo

VÍCEvláknové zpracování v C

Úvod:

V C, termín 'multitreading' popisuje použití četných vlákna současně. Každé vlákno dělá a jiný úkol . Vzhledem k souběžné povaze multithreadingu lze provádět mnoho úkolů najednou. Dodatečně, multithreading snižuje využití zdrojů CPU . Existují dvě kategorie multitaskingu: procesní a na bázi vláken . Když je cokoli popsáno jako multithreading, znamená to, že ve stejném procesu běží současně alespoň dvě nebo možná více vláken. Nejprve musíme porozumět tomu, co je vlákno a proces, abychom porozuměli multithreadingu v C. Podívejme se na tato témata, abychom lépe porozuměli.

numpy log

Co jsou procesy a vlákna?

A vlákno je základní budova blok provádění jakéhokoli procesu. Program se skládá z několika procesů a každý proces se skládá z vláken, což jsou mnohem základnější jednotky. Proto lze vlákno považovat za základní stavební blok procesu nebo jednodušší jednotku, která společně určuje využití CPU.

Ve vláknu jsou zahrnuty následující položky:

ID vlákna:

Je to speciál ID vlákna který je generován v době vytváření vlákna a uchováván po dobu trvání tohoto konkrétního vlákna.

Počítadlo programů:

Je to hodnota, kterou zatížení hardwaru .

Registrovaná sada:

Jedná se o sbírku společné registry .

Zásobník:

Je to pozůstatek toho konkrétní vlákno .

Kromě toho, pokud dvě vlákna pracují současně ve stejném procesu, sdílejí kód , datové sekce a další prostředky operačního systému, jako je soubor otevře a signály . Těžký proces, typ konvenčního procesu, může řídit jedno vlákno. Vícevláknové řízení má však kapacitu otevřít a provádět více úkolů současně. Systém se používáním vláken výrazně zefektivňuje, a proto jsou užitečná.

Rozdíl mezi singl a multithreading v C je vysvětleno. V první řadě se jedná o a jednovláknový proces . Výsledkem je, že celý blok včetně kód, data, atd.-je považován za jeden proces a tento proces má pouze jedno vlákno. Znamená to, že tato technika dokončí pouze jeden úkol najednou. Ale existuje vícevláknový proces která stojí proti tomu. Jsou tam aktivity jako kód, zásobník, data , a soubory také, ale jsou prováděny několika vlákny, z nichž každé má svůj vlastní zásobník a registry. Vzhledem k tomu, že v této situaci lze dokončit mnoho úkolů najednou, je proces známý jako a vícevláknový proces .

Vlákno se dodává ve dvou variantách:

Vlákno na uživatelské úrovni:

Je to na uživatelské úrovni, jak by název napovídal. Jádro nemá přístup ke svým datům.

Vlákno na úrovni jádra

Druh vlákna odkazuje na vztah vlákna k jádru a operačnímu systému systému.

Proces- Sérii kroků podniknutých k provedení programu lze označit jako proces . Program není při spuštění okamžitě spuštěn. Je rozdělen do několika základních kroků, které se provádějí postupně organizovaným způsobem, aby nakonec vedly k provedení procesu.

Proces, který byl rozdělen do menších kroků, se nazývá a 'klon nebo podřízený proces', zatímco původní proces je označován jako „rodičovský“ proces . V paměti každý proces využívá určité množství prostoru, který není sdílen s žádnými jinými procesy.

Postup prochází několika fázemi před provedením.

NOVÝ-

V této situaci je nový proces vytvořené .

PŘIPRAVENO-

Když je proces připraven a čeká na přiřazení procesoru, nachází se v tomto stavu.

BĚH-

Když je proces aktivní, je to stav.

ČEKÁNÍ-

bajtů na řetězec python

Když je proces v tomto stavu, něco je čekání stát se.

UKONČENO-

hranatý materiál

Je to stav, ve kterém se postup provádí.

Proč je C vícevláknové?

Vícevláknové zpracování v myšlence C lze využít paralelismus ke zlepšení an funkčnost aplikace . Zvažte případ, kdy máte v okně prohlížeče otevřeno několik karet. Potom každá záložka funguje souběžně a může být označována jako a Vlákno . Za předpokladu, že používáme Microsoft Excel , jedno vlákno zvládne formátování textu , a jedno vlákno bude manipulovat se vstupem . Proto funkce multithreadingu C usnadňuje provádění více úloh najednou. Vytvoření vlákna je podstatně rychlejší. Přenos kontextu mezi vlákny probíhá rychleji. Navíc lze komunikaci mezi vlákny provést rychleji a ukončení vlákna je jednoduché.

Jak psát programy C pro multithreading?

Ačkoli multithreadingové aplikace nejsou integrovány do jazyka C, je to možné v závislosti na operačním systému. The standardní knihovna threads.h se používá k implementaci myšlenky multithreadingu C . V současnosti však neexistuje žádný kompilátor, který by to dokázal. Musíme použít implementace specifické pro platformu, jako je např „POSIX“ knihovny vláken pomocí hlavičkového souboru pthread.h , pokud chceme používat multithreading v C. 'Pthreads' je pro to jiný název. A POSIX vlákno lze vytvořit následujícími způsoby:

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

V tomto případě, Pthread_create vytvoří nové vlákno, aby bylo vlákno spustitelné. Umožňuje vám implementovat multithreading v C tolikrát, kolikrát chcete ve svém kódu. Zde jsou uvedeny parametry a jejich popisy z dříve.

vlákno:

Je to a singulární identifikace že subproces se vrací .

attr:

Když chceme nastavit atributy vlákna, použijeme toto neprůhledný atribut .

start_rutina:

Když start_rutina je vygenerován, vlákno spustí rutinu.

argument:

Parametr, který start_rutina přijímá. NULA se použije, pokud nejsou uvedeny žádné argumenty.

Některé příklady C multithreading

Zde je několik příkladů problémů s vícevlákny v C.

1. Problém čtenář-zapisovatel

Častým problémem operačního systému se synchronizací procesů je problém se čtenářem/zapisovatelem . Předpokládejme, že máme databázi, že Čtenáři a Spisovatelé , mají přístup dvě různé kategorie uživatelů. Čtenáři jsou jediní, kteří mohou číst databáze, zatímco Spisovatelé jsou jediní, kdo může číst databázi a také ji aktualizovat. Pojďme použít IRCTC jako jednoduchý příklad. Pokud chceme zkontrolovat stav konkrétního číslo vlaku , jednoduše zadejte číslo vlaku do systému pro zobrazení příslušných informací o vlaku. Zde se zobrazují pouze informace, které jsou na webu. Operátor čtení je toto. Pokud si však chceme rezervovat letenku, musíme vyplnit rezervační formulář s údaji, jako je naše jméno, věk a podobně. Takže zde provedeme operaci zápisu. Budou provedeny určité úpravy databáze IRCTC .

Problém je v tom, že několik lidí se současně pokouší o přístup databáze IRCTC . Mohou být a spisovatel nebo a čtenář . Problém nastává, pokud čtenář již databázi využívá a zapisovatel k ní současně přistupuje, aby pracoval se stejnými daty. Další problém nastává, když zapisovač používá databázi a čtenář přistupuje ke stejným informacím jako databáze. Za třetí, existuje problém, když jeden zapisovač aktualizuje databázi, zatímco jiný se pokouší aktualizovat data ve stejné databázi. Čtvrtý scénář nastane, když se dva čtenáři pokusí získat stejný materiál. Všechny tyto problémy vznikají, pokud čtenář a zapisovač používají stejná data databáze.

Semafor je metoda, která se používá k řešení tohoto problému. Podívejme se na ilustraci, jak tento problém použít.

Proces čtenáře:

 #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;>

Vysvětlení:

V tomto kódu máme sdílená data proměnné a počet čtenářů ř . The wrt stav proměnná se používá k omezení přístupu pro spisovatelský proces a mutex se používá k zajištění vzájemného vyloučení přístupu ke sdíleným datům.

Čtenářský proces je reprezentován funkce reader(). . The počet čtenářů (rc) se zvyšuje před dosažením mutexový zámek . Používá pthread_cond_wait() čekat na wrt stav proměnná, pokud je první čtenář (rc == 1) . V důsledku toho bude pisatelům zabráněno v psaní, dokud to všichni čtenáři nedokončí.

Čtenářský proces zkontroluje, zda to bylo poslední čtenář (rc == 0) a snižuje čtenáře počítat (rc--) po přečtení sdílených dat. Kdyby to bylo, pthread_cond_signal() signalizuje wrt stav proměnná, aby mohly procesy čekajícího zapisovače pokračovat.

Za použití pthread_create() a funkce pthread_join(). , my Nový a připojit více čtenářských vláken v hlavní funkce . Každému čtenářskému vláknu je přiřazeno individuální ID pro účely identifikace.

Proces psaní:

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

Ve výše uvedeném příkladu, stejně jako čtenářský proces , operace známá jako operace čekání se provádí na 'wrt' když si uživatel přeje získat přístup k datům nebo objektu. Poté nový uživatel nebude mít přístup k objektu. A jakmile uživatel dokončí zápis, provede se další signální operace wrt .

2. Problém se zamykáním a odemykáním:

Myšlenka a mutex se používá v multithreadingu v C, aby bylo zaručeno, že tam nebude a závodní podmínky mezi vlákna . Když několik vláken začne zpracovávat stejná data najednou, tato okolnost se nazývá závodění . Pokud však tyto okolnosti existují, musíme. Používáme zámek mutexu() a funkce unlock(). k zabezpečení konkrétní části kódu pro konkrétní vlákno. Takové, že jiné vlákno nemůže začít provádět stejnou operaci. The 'kritická sekce/region' je název této chráněné kódové oblasti. Před použitím sdílených zdrojů toho v určité oblasti hodně nastavíme, a jakmile je skončíme, odemkneme je ještě jednou.

Podívejme se na fungování mutexu pro zamykání a odemykání v multithreadingu v C:

Příklad:

 #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;>

Vysvětlení:

matice v jazyce c

V tomto výše uvedeném příkladu vysvětlíme, jak jsme zámek a odemknout určitá oblast kódu, která nás chrání před závodní situací. 'pthread_mutex_t' se používá jako an inicializátor ve výše uvedeném příkladu. 'pthread_mutex_lock' je pak psaný před začátkem kódu, který chceme zamknout. Poté je kódování, které chceme uzamknout, dokončeno. Poté je uzamčení kódu ukončeno pomocí 'pthread_mutex_unlock' ; v budoucnu nebude žádný kód v režimu uzamčení.

Problém filozofa stravování:

Jedním z klasických problémů se synchronizací je problém filozofa stolování . Je vyžadována jednoduchá alokace zdrojů pro několik procesů, ale neměla by vést k a patová situace nebo hlad . The problém filozofa stolování lze považovat za přímou reprezentaci řady procesů, z nichž každý vyžaduje zdroje. Vzhledem k tomu, že každý z těchto procesů vyžaduje alokaci zdrojů, je nutné tyto zdroje rozdělit mezi všechny procesy, aby se žádný proces nikdy nezasekl nebo nepřestal fungovat.

Předpokládejme, že v a. sedí pět filozofů stůl ve tvaru kruhu . V jednu chvíli jedí a jindy o něčem přemýšlejí. Kolem kulatého stolu jsou filozofové rovnoměrně rozmístěni na židlích. Uprostřed stolu je navíc miska rýže a pět hůlek pro každého filozofa. Když má filozofka pocit, že nemůže komunikovat se svými kolegy, kteří sedí poblíž.

Když filozofka dostane hlad, občas vezme do ruky dvě hůlky. Vybere si dvě hůlky od svých sousedů – jednu na ni vlevo, odjet a jeden na ní že jo - které jsou na dosah. Filosof by ale nikdy neměl vzít do ruky více než jednu hůlku najednou. Zjevně nebude schopna zvednout hůlku, kterou používá soused.

Příklad:

Použijme příklad k demonstraci toho, jak je to implementováno v 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;>

Vysvětlení:

Tyčinky může být reprezentován semaforem. Protože existují tyčinky na stole a žádný filozof si nevybral žádnou, všechny součásti hůlek jsou nejprve inicializovány 1 . Teď tohle hůlka[i] byl vybrán jako první hůlka. hůlka[i] a hůlka[(i+1)%5] podléhají první operaci čekání. Tyto čekací operace hůlek naznačuje, že je filozof sebral. Proces stravování začíná, jakmile si filozof vybere ten svůj hůlka . Operace signálu se nyní provádí na hůlky [i] a [(i+1)%5] jakmile filozof dojedl. Filosof se pak vrátí ke spánku.

datum převodu řetězce

Chcete-li zjistit, zda podvlákno se připojil k hlavnímu vláknu nebo ne, použili jsme funkce pthread_join . Podobně jsme zkontrolovali, zda mutex zámek byl inicializován pomocí pthread_mutex_init metoda.

K inicializaci a ověření, zda bylo nové vlákno vytvořeno nebo ne, jsme použili funkce pthread_create . Podobně jako toto jsme zničili mutexový zámek za použití pthread_mutex_destroy funkce.

Problém producent-spotřebitel:

Častým problémem při synchronizaci vícevláknových procesů je problém producent-spotřebitel . Jsou v něm přítomny dva procesy: první je proces výrobce , a druhý je spotřebitelský proces . Dále se předpokládá, že obě operace probíhají souběžně a paralelně. Navíc se jedná o kooperativní proces, což znamená, že spolu něco sdílejí. Je důležité, že když je vyrovnávací paměť plný , výrobce nemůže přidat data. Když je vyrovnávací paměť prázdná, spotřebitel nemůže extrahovat data z vyrovnávací paměti, protože velikost vyrovnávací paměti mezi výrobcem a spotřebitelem je společná pevný . Problém je uveden tímto způsobem. Proto, abychom implementovali problém producent-spotřebitel a vyřešili jej, použijeme myšlenku paralelního programování.

Příklad:

 #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); } 

Výstup:

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

Vysvětlení:

Plníme dva úkoly. Funkce spotřebitel() a výrobce() indikují stav a provoz spotřebitel a výrobce . The metoda producent(). vytvoří mutexový zámek a určit, zda je vyrovnávací paměť plný když se to říká. Když je vyrovnávací paměť plná, nic se nevyrábí. Pokud ne, bude vytvořit a poté, po Výroba , sám se uspí, aby odemkl mutexový zámek . Jako výrobce , spotřebitel nejprve vytvoří mutexový zámek , zkontroluje vyrovnávací paměť , spotřebuje produkt a poté uvolní zámek, než se vrátí do režimu spánku.

A počítadlo (x) budou použity při výrobě a budou dále růst, dokud výrobce předmět nevyrobí. Spotřebitel však vyrobí méně stejných vyrobených kusů položka (x) .

Závěr:

Myšlenka použití dva nebo více vláken spustit program je známý jako multithreading v programovacím jazyce C. Vícevláknové zpracování umožňuje současné provádění několika úkolů. Nejjednodušší spustitelnou součástí programu je a vlákno . Proces je myšlenka, že úkol lze dokončit jeho rozdělením na několik menších dílčích procesů .

Soubor záhlaví pthread.h je vyžadována pro implementaci multithreadingu v C, protože to nelze provést přímo.