logo

TÖBBSZÁLA C-BEN

Bevezetés:

C-ben a kifejezés 'többszálas' számos felhasználását írja le szálak egyidejűleg. Minden szál a eltérő feladat . A többszálú feldolgozás párhuzamos jellege miatt sok feladatot lehet egyszerre végrehajtani. Ezenkívül többszálú csökkenti a A CPU erőforrás-használata . A multitaskingnak két kategóriája van: folyamat alapú és szál alapú . Ha bármit többszálúnak nevezünk, az azt jelenti, hogy legalább két vagy több szál fut egyszerre ugyanabban a folyamatban. Először is meg kell értenünk, hogy mi a szál és a folyamat, hogy megértsük a többszálas működést C-ben. Nézzük meg ezeket a témákat, hogy jobban megértsük.

árja kán

Mik azok a folyamatok és szálak?

A cérna az a alapvető épület Blokk bármely folyamat végrehajtásáról. Egy program több folyamatból áll, és mindegyik folyamat szálakból áll, amelyek sokkal alapvetőbb egységek. Ezért a szál egy folyamat alapvető építőelemének vagy egyszerűbb egységnek tekinthető, amely együttesen határozza meg a CPU kihasználtságát.

A következő elemek szerepelnek egy szálban:

Szál azonosító:

Ez egy különleges szál azonosítója amely a szál kialakításakor jön létre és az adott szál időtartamáig megmarad.

Program számláló:

Ez egy érték, amit a hardver terhelések .

Regisztrált készlet:

Ez egy gyűjtemény közös regiszterek .

Egy verem:

Ennek maradványa konkrét szál .

Ezen túlmenően, ha két szál egyszerre működik ugyanabban a folyamatban, akkor osztoznak kód , adatszakaszokat és egyéb operációs rendszer-erőforrások, például a fájl megnyílik és jeleket . Egy nehézsúlyú folyamat, a hagyományos eljárás egy fajtája, egy szálat vezérelhet. A többszálú vezérlés azonban képes több feladat egyidejű megnyitására és végrehajtására. A rendszer jelentősen hatékonyabbá válik a szálak használatának köszönhetően, ezért hasznosak.

A különbség a között egyetlen és többszálú a C-ben meg van magyarázva. Először is ez a egyszálú folyamat . Ennek eredményeként a teljes blokk – beleértve a kód, adat, stb.- egy folyamatnak tekintendő, és ennek a folyamatnak csak egy szála van. Ez azt jelenti, hogy ez a technika egyszerre csak egy feladatot hajt végre. De van egy többszálú folyamat ami ezzel szemben áll. Vannak olyan tevékenységek, mint pl kód, verem, adat , és fájlokat is, de ezeket több szál hajtja végre, amelyek mindegyikének megvan a maga verem és regiszter. Tekintettel arra, hogy ebben a helyzetben számos feladat egyszerre elvégezhető, a folyamatot a többszálú folyamat .

A szál kétféle változatban kapható:

Szál felhasználói szinten:

mátrixszorzás c-ben

Ez felhasználói szinten van, ahogy a név is sugallja. A kernel nem kap hozzáférést az adataihoz.

Szál a kernel szintjén

A szál típusa a szálnak a kernelhez és a rendszer operációs rendszeréhez való viszonyára utal.

Folyamat- A program végrehajtása érdekében tett lépések sorozatát nevezhetjük a folyamat . A program nem fut le azonnal, amikor fut. Ez néhány alapvető lépésre bontható, amelyeket egymás után, szervezett módon hajtanak végre, és végül egy folyamat végrehajtásához vezetnek.

A kisebb lépésekre bontott folyamatot a „klón vagy gyermek eljárás”, míg az eredeti folyamatot a „szülői” folyamat . A memóriában minden folyamat egy bizonyos mennyiségű helyet használ, amely nincs megosztva más folyamatokkal.

Az eljárás végrehajtása előtt néhány szakaszon megy keresztül.

ÚJ-

Ebben a helyzetben egy új folyamat generált .

KÉSZ-

Amikor egy folyamat előkészítve van, és a processzor hozzárendelésére vár, akkor ebben az állapotban van.

FUTÁS-

Amikor a folyamat aktív, az állapot.

VÁRAKOZÁS-

Amikor egy folyamat ebben az állapotban van, akkor valami van várakozás megtörténni.

MEGSZÜNTETT-

Ez az az állapot, amelyben az eljárást lefolytatják.

Miért többszálú a C?

Többszálú a C ötletben a párhuzamosság révén kihasználható egy az alkalmazás funkcionalitása . Vegye figyelembe azt az esetet, amikor több lap van nyitva egy böngészőablakban. Ezután az egyes lapok párhuzamosan működnek, és a cérna . Feltéve, hogy használjuk Microsoft Excel , egy szál kezelni fogja szöveg formázása , és egy szál fog kezeli a bevitelt . Ezért a C többszálú funkciója egyszerűvé teszi több feladat egyidejű végrehajtását. A szál létrehozása lényegesen gyorsabb. A szálak közötti kontextus átvitel gyorsabban megy végbe. Ezenkívül a szálak közötti kommunikáció gyorsabban megvalósítható, és a szálak lezárása egyszerű.

java listnode

Hogyan írjunk C programokat többszálú feldolgozáshoz?

Bár a többszálú alkalmazások nincsenek beépítve a C nyelvbe, az operációs rendszertől függően lehetséges. A threads.h szabványos könyvtár a többszálas ötlet megvalósítására szolgál C . Jelenleg azonban nincs olyan fordító, amely ezt meg tudná tenni. Platform-specifikus implementációkat kell alkalmaznunk, mint pl 'POSIX' szálak könyvtárát a fejlécfájl használatával pthread.h , ha többszálat szeretnénk használni C-ben. 'Pszálak' ennek egy másik neve. A POSIX szál a következő módokon hozható létre:

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

Ebben az esetben, Pthread_create létrehoz egy új szálat, hogy a szálat végrehajthatóvá tegye. Lehetővé teszi, hogy a kódban annyiszor valósítson meg többszálat C-ben, ahányszor csak akarja. Itt találhatók a paraméterek és azok leírása a korábbiakból.

cérna:

Ez egy egyedi azonosítás hogy a alfolyamat visszatér .

attr:

Amikor szálattribútumokat akarunk beállítani, ezt használjuk átlátszatlan tulajdonság .

start_rutin:

Amikor start_rutin generálódik, a szál egy rutint fog futtatni.

arg:

Az a paraméter, amely a start_rutin kap. NULLA akkor kerül felhasználásra, ha nem adunk meg érveket.

Bizonyos C többszálú példák

Íme néhány példa a többszálas problémákra C-ben.

1. Az olvasó-író kérdés

Az operációs rendszer gyakori problémája a folyamatszinkronizálással kapcsolatban a olvasó/író probléma . Tegyük fel, hogy van egy adatbázisunk Olvasók és Írók , két különböző felhasználói kategória, férhet hozzá. Olvasók csak ők tehetik meg olvas az adatbázist, míg Írók csak azok tudják elolvasni az adatbázist és frissíteni is. Használjuk IRCTC egyszerű példaként. Ha egy adott állapotát szeretnénk ellenőrizni vonatszám , egyszerűen írja be a vonat számát a rendszerbe a vonatra vonatkozó információk megtekintéséhez. Itt csak a weboldalon található információk jelennek meg. A read operátor ez. Ha azonban jegyet akarunk foglalni, akkor ki kell töltenünk a jegyfoglalási űrlapot olyan adatokkal, mint a nevünk, életkorunk stb. Tehát itt egy írási műveletet hajtunk végre. Lesz néhány módosítás a IRCTC adatbázis .

A probléma az, hogy többen egyszerre próbálnak hozzáférni a IRCTC adatbázis . Lehetnek a író vagy a olvasó . A probléma akkor merül fel, ha egy olvasó már használja az adatbázist, és egy író egyszerre éri el, hogy ugyanazon az adatokon dolgozzon. Egy másik probléma akkor merül fel, ha egy író adatbázist használ, és az olvasó ugyanazokhoz az információkhoz fér hozzá, mint az adatbázis. Harmadszor, nehézséget okoz, ha az egyik író frissíti az adatbázist, miközben egy másik ugyanazon az adatbázison próbálja frissíteni az adatokat. A negyedik forgatókönyv akkor fordul elő, amikor két olvasó megpróbálja lekérni ugyanazt az anyagot. Mindezek a problémák akkor merülnek fel, ha az olvasó és az író ugyanazokat az adatbázisadatokat használja.

A szemafor egy módszer, amelyet a probléma megoldására alkalmaznak. Nézzünk egy illusztrációt a probléma használatára.

Olvasási folyamat:

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

Magyarázat:

Ebben a kódban a megosztott változó adatok és a olvasók száma rc . A wrt állapot változó a hozzáférés korlátozására szolgál írói folyamat , és a mutex a megosztott adatokhoz való hozzáférés kölcsönös kizárásának garantálására szolgál.

Az olvasói folyamatot a Reader() függvény . A olvasók száma (rc) növelése előtt eléri a mutex zár . Használja pthread_cond_wait() várni a wrt állapot változó, ha ez a első olvasó (rc == 1) . Ennek eredményeként az írók nem tudnak írni, amíg az összes olvasó be nem fejezi.

Az olvasó folyamat ellenőrzi, hogy ez volt-e a utolsó olvasó (rc == 0) és leengedi az olvasót szám (rc--) a megosztott adatok elolvasása után. Ha volt, pthread_cond_signal() jelzi a wrt állapot változó, amely lehetővé teszi a várakozó írói folyamatok folytatását.

Használni a pthread_create() és pthread_join() függvények , mi új és csatlakozik több olvasói szál a fő funkció . Minden olvasószálhoz egyedi azonosító van hozzárendelve azonosítás céljából.

Írási folyamat:

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

A fenti példában ugyanaz, mint a olvasói folyamat , a várakozási műveletként ismert műveletet hajtják végre 'wrt' amikor a felhasználó hozzá kíván férni az adatokhoz vagy objektumokhoz. Ezt követően az új felhasználó nem fog tudni hozzáférni az objektumhoz. És amint a felhasználó befejezte az írást, egy újabb jelművelet kerül végrehajtásra wrt .

2. zárolási és feloldási probléma:

Az ötlet a mutex A többszálú C nyelvben használatos annak biztosítására, hogy ne legyen a verseny állapota között szálak . Ha több szál egyszerre kezdi feldolgozni ugyanazt az adatot, ezt a körülményt úgy ismerjük, mint verseny . Ha azonban ezek a körülmények fennállnak, meg kell tennünk. Használjuk a mutex zár () és unlock() függvények hogy biztosítson egy adott kódrészletet egy adott szálhoz. Így egy másik szál nem kezdheti el ugyanazt a műveletet. A „kritikus szakasz/régió” ennek a védett kódterületnek a neve. A megosztott erőforrások használata előtt sok mindent beállítunk egy adott területen, és miután befejeztük a használatukat, még egyszer feloldjuk őket.

Vizsgáljuk meg a mutex működését a zároláshoz és a feloldáshoz többszálú C-ben:

Példa:

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

Magyarázat:

reactjs térkép

Ebben a fenti példában elmagyarázzuk, hogyan zár és kinyit egy bizonyos kódrégió, amely megvéd minket a versenyhelyzettől. 'pthread_mutex_t' mint egy inicializáló a fenti példában. 'pthread_mutex_lock' akkor van írott a zárolni kívánt kód eleje előtt. A zárolni kívánt kódolás ezután befejeződik. Ezt követően a kód zárolása a használatával megszűnik 'pthread_mutex_unlock' ; a továbbiakban egyetlen kód sem lesz zár módban.

Az étkezési filozófus probléma:

A szinkronizálás egyik klasszikus problémája az étkezési filozófus kérdés . Több folyamathoz egyszerű erőforrás-allokáció szükséges, de ez nem eredményezheti a patt vagy éhség . A étkezési filozófus probléma egy sor olyan folyamat egyszerű ábrázolásának tekinthető, amelyek mindegyike erőforrásigényes. Mivel ezeknek a folyamatoknak mindegyike erőforrás-allokációt igényel, ezeket az erőforrásokat az összes folyamat között el kell osztani, hogy egyetlen folyamat se akadjon el vagy ne álljon le.

Tegyük fel, hogy öt filozófus ül a kör alakú asztal . Egyik ponton esznek, máskor meg elgondolkoznak valamin. A kerek asztal körül a filozófusok egyenletesen helyezkednek el a székeken. Ezenkívül minden filozófus számára van egy tál rizs és öt pálcika az asztal közepén. Amikor a filozófus úgy érzi, nem tud kapcsolatba lépni a közelben ülő kollégáival.

Egy filozófus időnként felvesz két pálcikát, amikor megéhezik. Két pálcikát választ a szomszédaitól – egyet rajta bal és egy rajta jobb - amelyek könnyen elérhetőek. De a filozófus soha ne vegyen fel egynél több pálcikát egyszerre. Nyilvánvalóan képtelen lesz felvenni a pálcikát, amit a szomszéd használ.

Példa:

Használjunk egy példát annak bemutatására, hogy ez hogyan valósul meg C-ben.

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

Magyarázat:

Kínai evőpálcikák szemaforral ábrázolható. Mivel vannak kínai evőpálcikák az asztalon, és egyetlen filozófus sem választott egyet, az evőpálcika összes összetevőjét először inicializálják 1 . Most, hogy pálcika[i] elsőnek választották pálcika. pálcika[i] és pálcika [(i+1)%5] az első várakozási művelet hatálya alá tartoznak. Ezek pálcika-váró művelet azt jelzi, hogy a filozófus felvette őket. Az étkezési folyamat akkor kezdődik, amikor a filozófus kiválasztja a magáét pálcika . A jelművelet most a készüléken történik pálcika [i] és [(i+1)%5] ha a filozófus befejezte az evést. A filozófus ezután visszaalszik.

Annak megállapítására, hogy a részszál csatlakozott-e a főszálhoz vagy sem, mi a pthread_join függvény . Hasonlóképpen ellenőriztük, hogy a mutex A zár inicializálása a pthread_mutex_init módszer.

java volatile kulcsszó

Az inicializáláshoz és annak ellenőrzéséhez, hogy az új szál létrejött-e vagy sem, a pthread_create függvény . Ehhez hasonlóan megsemmisítettük a mutex zár használni a pthread_mutex_destroy funkció.

A termelő-fogyasztó probléma:

A többszálú folyamatszinkronizálás gyakori problémája a termelő-fogyasztó probléma . Két folyamat van jelen benne: az első az termelői folyamat , a második pedig a fogyasztói folyamat . Továbbá feltételezzük, hogy mindkét művelet párhuzamosan történik. Ráadásul ezek egy kooperatív folyamat, ami azt jelenti, hogy valamit megosztanak egymással. Fontos, hogy amikor a puffer van teljes , a gyártó nem tud adatokat hozzáadni. Ha a puffer üres, a fogyasztó nem tud adatokat kinyerni a pufferből, mert a gyártó és a fogyasztó közötti közös pufferméret rögzített . A probléma így van megfogalmazva. Ezért a termelő-fogyasztó probléma megvalósításához és megoldásához a párhuzamos programozás ötletét alkalmazzuk.

Példa:

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

Kimenet:

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

Magyarázat:

Két feladatot látunk el. A funkciókat fogyasztó() és termelő() jelzi az állapotát és működését fogyasztó és termelő . A producer() módszer létre fogja hozni a mutex zár és határozza meg, hogy a puffer az teljes amikor hívják. Amikor a puffer megtelik, semmi sem keletkezik. Ha nem, akkor lesz teremt , majd, miután a Termelés , elalszik, hogy feloldja a mutex zár . Mint a termelő , a fogyasztó először létrehozza a mutex zár , ellenőrzi a puffer , fogyasztja a termék , majd kioldja a zárat, mielőtt visszaalszik.

A számláló (x) A gyártás során felhasználják, és folyamatosan növekszik, amíg a gyártó le nem állítja a terméket. A fogyasztó azonban kevesebbet készít ugyanabból a termékből tétel (x) .

Következtetés:

A használat ötlete kettő vagy több szál egy program végrehajtása az úgynevezett többszálú C programozási nyelven. Többszálú több feladat egyidejű végrehajtását teszi lehetővé. A program legegyszerűbb végrehajtható komponense a cérna . A folyamat az az elképzelés, hogy egy feladat több kisebb részre bontásával is elvégezhető részfolyamatok .

A fejléc fájl pthread.h szükséges a többszálú feldolgozás C-ben való megvalósításához, mivel ez közvetlenül nem végezhető el.