logo

VIACvláknové spracovanie v C

Úvod:

V C, termín 'multithreading' opisuje použitie početných vlákna súčasne. Každé vlákno robí a iná úloha . Vzhľadom na súbežnú povahu multithreadingu je možné vykonať veľa úloh naraz. okrem toho multithreading znižuje využitie zdrojov CPU . Existujú dve kategórie multitaskingu: procesné a na báze vlákien . Keď je čokoľvek opísané ako multithreading, znamená to, že v rovnakom procese bežia naraz aspoň dve alebo možno viac vlákien. Najprv musíme pochopiť, čo je vlákno a proces, aby sme pochopili multithreading v C. Pozrime sa na tieto predmety, aby sme lepšie porozumeli.

odstrániť súbor v java

Čo sú procesy a vlákna?

A niť je základná budova blokovať vykonania akéhokoľvek procesu. Program sa skladá z niekoľkých procesov a každý proces sa skladá z vlákien, ktoré sú oveľa základnejšími jednotkami. Preto možno vlákno považovať za základný stavebný kameň procesu alebo jednoduchšiu jednotku, ktorá spoločne určuje využitie CPU.

Vo vlákne sú zahrnuté nasledujúce položky:

ID vlákna:

Je to špeciál ID vlákna ktorý sa generuje v čase vytvárania vlákna a uchováva sa počas trvania tohto konkrétneho vlákna.

Počítadlo programov:

Je to hodnota, ktorú zaťaženie hardvéru .

Registrovaná sada:

Ide o kolekciu spoločné registre .

Zásobník:

Je to pozostatok toho konkrétne vlákno .

Okrem toho, ak dve vlákna pracujú súčasne v rovnakom procese, zdieľajú sa kód , dátové sekcie a ďalšie prostriedky operačného systému, ako je súbor otvára a signály . Ťažký proces, typ konvenčného procesu, môže riadiť jedno vlákno. Viacvláknové riadenie má však schopnosť otvárať a vykonávať viacero úloh súčasne. Systém sa vďaka používaniu vlákien výrazne zefektívni, a preto sú užitočné.

Rozdiel medzi slobodný a multithreading v C je vysvetlené. V prvom rade ide o a jednovláknový proces . Výsledkom je, že celý blok vrátane kód, údaje, atď. - sa považuje za jeden proces a tento proces má iba jedno vlákno. Znamená to, že táto technika vykoná naraz iba jednu úlohu. Ale existuje a viacvláknový proces ktorý stojí v opozícii voči tomuto. Sú tam aktivity ako kód, zásobník, dáta , a súbory tiež, ale sú vykonávané niekoľkými vláknami, z ktorých každé má svoj vlastný zásobník a registre. Vzhľadom na to, že v tejto situácii je možné vykonať viacero úloh naraz, proces je známy ako a viacvláknový proces .

Niť sa dodáva v dvoch variantoch:

Vlákno na úrovni používateľa:

Je to na úrovni používateľa, ako by už názov napovedal. Jadro nemá prístup k svojim údajom.

Vlákno na úrovni jadra

Druh vlákna odkazuje na vzťah vlákna k jadru a operačnému systému systému.

proces- Séria krokov vykonaných na vykonanie programu môže byť označovaná ako proces . Program sa pri spustení nespustí okamžite. Je rozdelená do niekoľkých základných krokov, ktoré sa vykonávajú postupne organizovaným spôsobom, aby nakoniec viedli k vykonaniu procesu.

Proces, ktorý bol rozdelený na menšie kroky, sa označuje ako a 'klon alebo podriadený proces', zatiaľ čo pôvodný proces sa označuje ako „rodičovský“ proces . V pamäti každý proces využíva určité množstvo priestoru, ktorý nie je zdieľaný so žiadnymi inými procesmi.

Postup prechádza niekoľkými fázami pred vykonaním.

pothineni baran

NOVÝ-

V tejto situácii ide o nový proces generované .

PRIPRAVENÝ-

Keď je proces pripravený a čaká na pridelenie procesora, nachádza sa v tomto stave.

BEH-

Keď je proces aktívny, je to stav.

ČAKANIE-

Keď je proces v tomto stave, niečo je čakanie stať sa.

UKONČENÉ-

hlavné java

Je to stav, v ktorom sa postup vykonáva.

Prečo je C viacvláknové?

Multithreading v myšlienke C možno využiť paralelizmus na zlepšenie an funkčnosť aplikácie . Zvážte prípad, keď máte v okne prehliadača otvorených niekoľko kariet. Potom každá záložka funguje súbežne a možno ju označovať ako a Niť . Za predpokladu, že používame Microsoft Excel , jedno vlákno zvládne formátovanie textu , a jedno vlákno bude zvládnuť vstup . Preto funkcia multithreading v C uľahčuje vykonávanie viacerých úloh naraz. Vytvorenie vlákna je podstatne rýchlejšie. Prenos kontextu medzi vláknami prebieha rýchlejšie. Navyše, komunikácia medzi vláknami môže byť rýchlejšia a ukončenie vlákna je jednoduché.

Ako písať programy C pre viacvláknové spracovanie?

Hoci multithreadingové aplikácie nie sú zabudované do jazyka C, je to možné v závislosti od operačného systému. The štandardná knižnica threads.h sa používa na implementáciu myšlienky multithreadingu v C . V súčasnosti však neexistuje žiadny kompilátor, ktorý by to dokázal. Musíme použiť implementácie špecifické pre platformu, ako je napr „POSIX“ vláknami pomocou súboru hlavičky pthread.h , ak chceme použiť multithreading v C. 'pthreads' je pre to iný názov. A POSIX vlákno je možné vytvoriť nasledujúcimi spôsobmi:

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

V tomto prípade, Pthread_create vytvorí nové vlákno, aby bolo vlákno spustiteľné. Umožňuje vám implementovať multithreading v C toľkokrát, koľkokrát chcete vo svojom kóde. Parametre a ich popisy z predchádzajúceho sú uvedené tu.

vlákno:

Je to a jednotná identifikácia že subproces sa vracia .

attr:

Keď chceme nastaviť atribúty vlákna, použijeme to nepriehľadný atribút .

štart_rutina:

Kedy štart_rutina sa vygeneruje, vlákno spustí rutinu.

arg:

Parameter, ktorý štart_rutina prijíma. NULOVÝ sa použije, ak nie sú uvedené žiadne argumenty.

Niektoré C multithreading príklady

Tu je niekoľko príkladov problémov s viacerými vláknami v C.

1. Problém čitateľ-zapisovateľ

Bežným problémom operačného systému so synchronizáciou procesov je problém čitateľa/zapisovateľa . Predpokladajme, že máme databázu, ktorá Čitatelia a Spisovatelia , majú prístup k dvom rôznym kategóriám používateľov. Čitatelia sú jediní, ktorí môžu čítať databáze, keďže Spisovatelia sú jediní, ktorí môžu čítať databázu a tiež ju aktualizovať. Využime IRCTC ako jednoduchý príklad. Ak chceme skontrolovať stav konkrétneho číslo vlaku , jednoducho zadajte číslo vlaku do systému pre zobrazenie príslušných informácií o vlaku. Zobrazujú sa tu iba informácie, ktoré sú uvedené na webovej stránke. Operátor čítania je toto. Ak si však chceme rezervovať letenku, musíme vyplniť rezervačný formulár letenky s údajmi ako naše meno, vek a podobne. Takže tu vykonáme operáciu zápisu. Vykonajú sa určité úpravy Databáza IRCTC .

Problém je v tom, že niekoľko ľudí sa súčasne pokúša o prístup Databáza IRCTC . Môžu byť a spisovateľ alebo a čitateľ . Problém nastáva, ak čitateľ už databázu používa a zapisovateľ k nej pristupuje súčasne, aby pracoval s rovnakými údajmi. Ďalší problém vzniká, keď zapisovateľ používa databázu a čitateľ má prístup k rovnakým informáciám ako databáza. Po tretie, existuje problém, keď jeden zapisovač aktualizuje databázu, zatiaľ čo iný sa pokúša aktualizovať údaje v tej istej databáze. Štvrtý scenár nastane, keď sa dvaja čitatelia pokúsia získať rovnaký materiál. Všetky tieto problémy vznikajú, ak čitateľ a zapisovač používajú rovnaké údaje databázy.

Semafor je metóda, ktorá sa používa na riešenie tohto problému. Pozrime sa na ilustráciu použitia tohto problému.

Proces čítania:

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

Vysvetlenie:

V tomto kóde máme zdieľané premenné dáta a počet čitateľov rc . The wrt stav premenná sa používa na obmedzenie prístupu pre spisovateľský proces , a mutex sa používa na zaručenie vzájomného vylúčenia prístupu k zdieľaným údajom.

Čitateľský proces predstavuje funkcia reader(). . The počet čitateľov (rc) sa zvyšuje pred dosiahnutím mutexový zámok . Používa sa pthread_cond_wait() čakať na wrt stav premenná, ak je prvý čitateľ (rc == 1) . Výsledkom bude, že pisatelia nebudú môcť písať, kým to nedokončia všetci čitatelia.

Proces čítania skontroluje, či to bolo posledný čitateľ (rc == 0) a znižuje čitateľa počítať (rc--) po prečítaní zdieľaných údajov. Ak by bolo, pthread_cond_signal() signalizuje wrt stav premenná, aby mohli čakacie procesy zapisovača pokračovať.

Pomocou pthread_create() a funkcie pthread_join(). , my Nový a pripojiť sa viaceré čitateľské vlákna v funkcia main(). . Každému vláknu čítačky je priradené individuálne ID na účely identifikácie.

Proces spisovateľa:

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

Vo vyššie uvedenom príklade, rovnako ako čitateľský proces sa vykonáva operácia známa ako operácia čakania 'wrt' keď používateľ chce získať prístup k údajom alebo objektu. Potom nový používateľ nebude mať prístup k objektu. A keď používateľ dokončí zápis, vykoná sa ďalšia operácia signálu wrt .

2. problém so zamknutím a odomknutím:

Myšlienka a mutex sa používa v multithreading v C, aby sa zaručilo, že tam nebude a rasový stav medzi vlákna . Keď viaceré vlákna začnú spracovávať rovnaké údaje naraz, táto okolnosť je známa ako pretekanie . Ak však tieto okolnosti existujú, musíme. Používame zámok mutexu() a funkcie unlock(). na zabezpečenie konkrétnej časti kódu pre konkrétne vlákno. Tak, že iné vlákno nemôže začať vykonávať rovnakú operáciu. The 'kritická sekcia/región' je názov tejto chránenej kódovej oblasti. Pred použitím zdieľaných zdrojov veľa nastavíme v určitej oblasti a keď ich skončíme, znova ich odomkneme.

Pozrime sa na fungovanie mutexu na zamykanie a odomykanie v multithreadingu v C:

Prí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;>

Vysvetlenie:

matice v jazyku c

V tomto vyššie uvedenom príklade vysvetlíme, ako sme zámok a odomknúť určitá oblasť kódu, ktorá nás chráni pred pretekárskou situáciou. 'pthread_mutex_t' sa používa ako an inicializátor v príklade vyššie. 'pthread_mutex_lock' je potom napísané pred začiatkom kódu, ktorý chceme uzamknúť. Potom je kódovanie, ktoré chceme uzamknúť, hotové. Potom sa uzamknutie kódu ukončí pomocou 'pthread_mutex_unlock' ; v budúcnosti nebude žiadny kód v režime uzamknutia.

q3 mesiace

Problém filozofa stravovania:

Jedným z klasických problémov so synchronizáciou je otázka filozofa stolovania . Vyžaduje sa jednoduché pridelenie zdrojov pre niekoľko procesov, ale nemalo by viesť k a patová situácia alebo hlad . The problém filozofa stolovania možno považovať za priamu reprezentáciu množstva procesov, z ktorých každý je náročný na zdroje. Keďže každý z týchto procesov vyžaduje alokáciu zdrojov, je potrebné tieto zdroje rozdeliť medzi všetky procesy, aby sa žiadny proces nikdy nezasekol alebo neprestal fungovať.

Predpokladajme, že pri a. sedí päť filozofov stôl v tvare kruhu . V jednej chvíli jedia a inokedy o niečom premýšľajú. Okolo okrúhleho stola sú filozofi rovnomerne rozmiestnení na stoličkách. Okrem toho je v strede stola miska ryže a päť paličiek pre každého filozofa. Keď má filozofka pocit, že nemôže komunikovať so svojimi kolegami, ktorí sedia neďaleko.

Keď filozofka dostane hlad, príležitostne vezme do ruky dve paličky. Vyberie si dve paličky od svojich susedov – jednu na ňu vľavo a jeden na ňu správny - ktoré sú na dosah ruky. Filozof by však nikdy nemal zdvihnúť viac ako jednu paličku naraz. Zjavne nebude schopná zdvihnúť paličku, ktorú používa sused.

Príklad:

Použime príklad na demonštráciu toho, ako je to implementované 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;>

Vysvetlenie:

Paličky môžu byť reprezentované semaforom. Keďže existujú paličky na stole a žiadny filozof si nevybral žiadnu, všetky komponenty paličiek sa najprv inicializujú na 1 . Teraz to palička[i] bol vybraný ako prvý palička. palička[i] a palička[(i+1)%5] podliehajú prvej operácii čakania. Títo čakacia operácia paličiek naznačuje, že filozof ich zachytil. Proces jedenia začína, keď si filozof vyberie to svoje palička . Operácia signálu sa teraz vykonáva na paličky [i] a [(i+1)%5] keď filozof dojedol. Filozof sa potom vráti k spánku.

Ak chcete zistiť, či podvlákno sa pripojil k hlavnému vláknu alebo nie, použili sme funkcia pthread_join . Podobne sme skontrolovali, či mutex zámok bol inicializovaný pomocou pthread_mutex_init metóda.

Na inicializáciu a overenie, či bolo nové vlákno vytvorené alebo nie, sme použili funkcia pthread_create . Podobne ako toto sme zničili mutexový zámok pomocou pthread_mutex_destroy funkciu.

Problém producent-spotrebiteľ:

Bežným problémom pri synchronizácii viacvláknového procesu je problém producent-spotrebiteľ . Sú v ňom prítomné dva procesy: prvý je proces výrobcu , a druhý je proces spotrebiteľa . Ďalej sa predpokladá, že obe operácie prebiehajú súbežne a paralelne. Okrem toho ide o kooperatívny proces, čo znamená, že spolu niečo zdieľajú. Je dôležité, že keď je vyrovnávacia pamäť plný , výrobca nemôže pridať údaje. Keď je vyrovnávacia pamäť prázdna, spotrebiteľ nemôže extrahovať údaje z vyrovnávacej pamäte, pretože medzi výrobcom a spotrebiteľom je spoločná veľkosť vyrovnávacej pamäte pevné . Problém je uvedený týmto spôsobom. Preto, aby sme implementovali problém producent-spotrebiteľ a vyriešili ho, použijeme myšlienku paralelného programovania.

Prí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ýkon:

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

Vysvetlenie:

Vykonávame dve úlohy. Funkcie spotrebiteľ() a producent() indikujú stav a prevádzku spotrebiteľ a výrobca . The metóda producent(). vytvorí mutexový zámok a určiť, či je vyrovnávacia pamäť plný keď sa volá. Keď je zásobník plný, nič sa nebude vyrábať. Ak nie, bude vytvoriť , a potom, po výroby , sám sa uspí, aby odomkol mutexový zámok . Ako výrobca , spotrebiteľ najskôr vytvorí mutexový zámok , kontroluje vyrovnávacej pamäte , spotrebuje produktu a potom uvoľní zámok pred návratom do režimu spánku.

A počítadlo (x) sa použije počas výroby a bude sa zväčšovať, kým výrobca nevyrobí položku. Spotrebiteľ však vyrobí menej rovnakých vyrobených kusov položka (x) .

Záver:

Myšlienka použitia dva alebo viac vlákien spustiť program je známy ako multithreading v programovacom jazyku C. Multithreading umožňuje súčasné vykonávanie niekoľkých úloh. Najjednoduchším spustiteľným komponentom programu je a niť . Proces je myšlienka, že úlohu možno dokončiť rozdelením na niekoľko menších čiastkové procesy .

Hlavičkový súbor pthread.h je potrebný na implementáciu multithreadingu v C, pretože to nemožno urobiť priamo.