logo

MULTITHREADING IN C

Introduzione:

In C, il termine 'multithreading' descrive l'uso di numerosi discussioni in concomitanza. Ogni thread fa a compito diverso . A causa della natura simultanea del multithreading, è possibile eseguire più attività contemporaneamente. Inoltre, multithreading riduce il Utilizzo delle risorse della CPU . Esistono due categorie di multitasking: basato sul processo E basato su thread . Quando qualcosa viene descritto come multithreading, significa che almeno due o forse più thread sono in esecuzione nello stesso processo contemporaneamente. Dobbiamo prima capire cosa sono un thread e un processo per comprendere il multithreading in C. Diamo un'occhiata a questi argomenti per ottenere una migliore comprensione.

concat.sql

Cosa sono i processi e i thread?

UN filo è il edificio fondamentale bloccare dell'esecuzione di qualsiasi processo. Un programma è composto da diversi processi e ogni processo è costituito da thread, che sono unità molto più basilari. Pertanto, il thread può essere considerato l'elemento fondamentale di un processo o l'unità più semplice che determina congiuntamente l'utilizzo della CPU.

I seguenti elementi sono inclusi in una discussione:

ID discussione:

È speciale ID del thread che viene generato al momento della formazione del thread e conservato per la durata di quel thread specifico.

Contatore di programma:

È un valore che il carichi hardware .

Un insieme registrato:

È una raccolta di registri comuni .

Una pila:

Ne è un residuo filo specifico .

Inoltre, se due thread lavorano contemporaneamente nello stesso processo, condividono codice , sezioni dati e altre risorse del sistema operativo come file si apre E segnali . Un processo pesante, un tipo di processo convenzionale, può controllare un thread. Tuttavia, un multi-thread di controllo ha la capacità di aprire ed eseguire più attività contemporaneamente. Il sistema diventa notevolmente più efficace grazie all'utilizzo dei thread, motivo per cui sono utili.

La distinzione tra separare E multithreading in C è spiegato. Prima di tutto, è a processo a thread singolo . Di conseguenza, l'intero blocco, compreso il codice, dati, ecc.-è considerato come un processo e quel processo ha solo un thread. Significa che questa tecnica completerà solo un'attività alla volta. Ma c'è un processo multithread che si oppone a questo. Ci sono attività come codice, stack, dati , E File anch'essi, ma vengono eseguiti da diversi thread, ognuno dei quali ha il proprio stack e registri. Dato che in questa situazione è possibile completare numerose attività contemporaneamente, il processo è noto come a processo multithread .

Il filo è disponibile in due varietà:

Discussione a livello utente:

È a livello di utente, come suggerisce il nome. Il kernel non ha accesso ai suoi dati.

Discussione a livello di kernel

Il tipo di thread si riferisce alla relazione del thread con il kernel e il sistema operativo del sistema.

Processi- La serie di passaggi necessari per eseguire un programma può essere definita come processi . Un programma non viene eseguito immediatamente quando viene eseguito. È suddiviso in alcuni passaggi fondamentali che vengono eseguiti sequenzialmente in modo organizzato per portare alla fine all'esecuzione di un processo.

Un processo che è stato suddiviso in passaggi più piccoli viene definito a 'processo clone o figlio', mentre il processo originale è indicato come processo 'genitore'. . Nella memoria, ogni processo utilizza una certa quantità di spazio che non è condivisa con altri processi.

Una procedura attraversa alcune fasi prima dell'esecuzione.

javafx

NUOVO-

In questa situazione, un nuovo processo è generato .

PRONTO-

Quando un processo è preparato e attende l'assegnazione di un processore, si trova in questo stato.

CORSA-

Quando il processo è attivo, è lo stato.

IN ATTESA-

Quando un processo è in questo stato, qualcosa lo è in attesa accadere.

TERMINATO-

rotazione dell'albero avl

È lo stato in cui si svolge la procedura.

Perché il C è multithread?

Multithreading nel C l'idea può essere sfruttata attraverso il parallelismo per migliorare un funzionalità dell'applicazione . Considera il caso in cui hai diverse schede aperte in una finestra del browser. Quindi, ciascuna scheda funziona contemporaneamente e potrebbe essere denominata a Filo . Supponendo che usiamo Microsoft Excel , un thread gestirà formattazione del testo , e un thread lo farà gestire l'input . Pertanto, la funzionalità multithreading di C semplifica l'esecuzione di più attività contemporaneamente. La creazione di un thread è notevolmente più rapida. Il trasferimento del contesto tra i thread avviene più rapidamente. Inoltre, la comunicazione tra i thread può essere resa più rapida e la terminazione dei thread è semplice.

Come scrivere programmi C per il multithreading?

Sebbene le applicazioni multithreading non siano integrate nel linguaggio C, ciò è possibile a seconda del sistema operativo. IL libreria standard threads.h viene utilizzato per implementare l'idea del multithreading in C . Tuttavia, attualmente non esiste un compilatore in grado di farlo. Dobbiamo utilizzare implementazioni specifiche della piattaforma, come ad esempio 'POSIX' libreria threads, utilizzando il file header pthread.h , se vogliamo usare il multithreading in C. 'Thread' è un altro nome per questo. UN POSIX il thread può essere creato nei seguenti modi:

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

In questo caso, Pthread_create crea un nuovo thread per rendere eseguibile il thread. Ti consente di implementare il multithreading in C tutte le volte che vuoi nel tuo codice. I parametri e le relative descrizioni precedenti sono elencati qui.

filo:

È un identificazione singolare che il il sottoprocesso ritorna .

attr:

Quando vogliamo impostare gli attributi del thread, usiamo this attributo opaco .

routine_avvio:

Quando start_routine viene generato, il thread eseguirà una routine.

argomento:

Il parametro che il start_routine riceve. NULLO verrà utilizzato se non vengono forniti argomenti.

Alcuni esempi di multithreading C

Ecco alcuni esempi di problemi di multithreading in C.

1. La questione lettore-scrittore

Un problema comune del sistema operativo con la sincronizzazione dei processi è problema del lettore/scrittore . Supponiamo di avere un database che Lettori E Scrittori , possono accedere due diverse categorie di utenti. Lettori sono gli unici che possono Leggere il database, mentre Scrittori sono gli unici che possono leggere il database e aggiornarlo. Usiamo IRCTC come semplice esempio. Se desideriamo verificare lo stato di un file specific numero del treno , è sufficiente inserire il numero del treno nel sistema per visualizzare le informazioni pertinenti sul treno. Qui vengono mostrate solo le informazioni presenti sul sito web. L'operatore di lettura è questo. Tuttavia, se vogliamo prenotare un biglietto, dobbiamo compilare il modulo di prenotazione del biglietto con dettagli come il nostro nome, età e così via. Quindi, eseguiremo un'operazione di scrittura qui. Verranno apportate alcune modifiche al Banca dati IRCTC .

Il problema è che più persone tentano contemporaneamente di accedere al file Banca dati IRCTC . Potrebbero essere a scrittore o a lettore . Il problema sorge se un lettore sta già utilizzando il database e uno scrittore vi accede contemporaneamente per lavorare sugli stessi dati. Un altro problema sorge quando uno scrittore utilizza un database e un lettore accede alle stesse informazioni del database. In terzo luogo, c'è una difficoltà quando uno scrittore aggiorna il database mentre un altro tenta di aggiornare i dati sullo stesso database. Il quarto scenario si verifica quando due lettori tentano di recuperare lo stesso materiale. Tutti questi problemi sorgono se il lettore e lo scrittore utilizzano gli stessi dati del database.

Il semaforo è un metodo utilizzato per risolvere questo problema. Diamo un'occhiata a un'illustrazione di come utilizzare questo problema.

Processo di lettura:

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

Spiegazione:

In questo codice abbiamo i dati variabili condivisi e il file conteggio dei lettori rc . IL condizione sbagliata la variabile viene utilizzata per limitare l'accesso per il file processo dello scrittore , e il mutex viene utilizzato per garantire la mutua esclusione per l'accesso ai dati condivisi.

Il processo del lettore è rappresentato da funzione lettore() . IL conteggio lettori (rc) viene aumentato prima di raggiungere il blocco mutex . Utilizza pthread_cond_wait() aspettare il condizione sbagliata variabile se è la primo lettore (rc == 1) . Di conseguenza, agli scrittori verrà impedito di scrivere finché tutti i lettori non avranno completato.

Il processo di lettura controlla se era il file ultimo lettore (rc == 0) e abbassa il lettore contare (rc--) dopo aver letto i dati condivisi. Se fosse, pthread_cond_signal() segnala il condizione sbagliata variabile per consentire ai processi di scrittura in attesa di continuare.

Usando il pthread_create() E funzioni pthread_join() , Noi nuovo E giuntura più thread di lettori nel file funzione principale . Un ID individuale viene assegnato a ciascun thread del lettore a scopo identificativo.

Processo di scrittura:

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

Nell'esempio sopra, lo stesso di processo del lettore , viene eseguita un'operazione nota come operazione di attesa 'sbagliato' quando un utente desidera accedere ai dati o all'oggetto. Successivamente, il nuovo utente non sarà in grado di accedere all'oggetto. E una volta che l'utente ha finito di scrivere, viene eseguita un'altra operazione di segnale wrt .

2. problema di blocco e sblocco:

L'idea di a mutex viene utilizzato nel multithreading in C per garantire che non ci sia un file condizione di gara tra i discussioni . Quando più thread iniziano a elaborare gli stessi dati contemporaneamente, questa circostanza è nota come da corsa . Tuttavia, se queste circostanze esistono, dobbiamo. Noi usiamo il blocco del mutex() E funzioni sblocca() per proteggere una particolare sezione di codice per un thread specifico. In modo tale che un altro thread non possa iniziare a eseguire la stessa operazione. IL 'sezione/regione critica' è il nome dato a questa area di codice protetta. Prima di utilizzare le risorse condivise, predisponiamo molte cose in una determinata area e, una volta finito di utilizzarle, le sblocchiamo nuovamente.

Esaminiamo il funzionamento del mutex per il blocco e lo sblocco in multithreading in C:

Esempio:

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

Spiegazione:

Java confronta le stringhe

In questo esempio sopra, spieghiamo come we serratura E sbloccare una certa regione di codice che ci protegge dalla situazione delle corse. 'pthread_mutex_t' è usato come un inizializzatore nell'esempio sopra. 'pthread_mutex_lock' è poi scritto prima dell'inizio del codice che vogliamo bloccare. Successivamente la codifica che desideriamo bloccare sarà completata. Successivamente, il blocco del codice viene terminato utilizzando 'pthread_mutex_unlock' ; da ora in poi, nessun codice sarà in modalità di blocco.

concatenazione di stringhe java

Il problema del filosofo a tavola:

Uno dei classici problemi con la sincronizzazione è il file questione del filosofo a tavola . È necessaria una semplice allocazione delle risorse per diversi processi, ma non dovrebbe comportare a stallo O fame . IL problema del filosofo a tavola può essere visto come una rappresentazione semplice di una serie di processi, ognuno dei quali richiede risorse. Poiché ciascuno di questi processi richiede un'allocazione di risorse, è necessario distribuire tali risorse tra tutti i processi in modo che nessun processo si blocchi o smetta di funzionare.

Supponiamo che ci siano cinque filosofi seduti a tavolo a forma di cerchio . Mangiano ad un certo punto e riflettono su qualcosa in un altro. Attorno alla tavola rotonda i filosofi sono equamente distribuiti sulle sedie. Inoltre, al centro del tavolo c'è una ciotola di riso e cinque bacchette per ogni filosofo. Quando il filosofo sente di non poter interagire con i colleghi che le sono seduti accanto.

Un filosofo occasionalmente prende due bacchette quando ha fame. Sceglie due bacchette dai suoi vicini, una su di lei Sinistra e uno su di lei Giusto -che sono facilmente raggiungibili. Ma il filosofo non dovrebbe mai prendere in mano più di una bacchetta alla volta. Ovviamente non potrà prendere in mano la bacchetta usata dal vicino.

Esempio:

Usiamo un esempio per dimostrare come questo viene implementato in 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;>

Spiegazione:

Bacchette può essere rappresentato da un semaforo. Dato che ci sono bacchette sul tavolo e nessun filosofo ne ha scelto uno, tutti i componenti delle bacchette vengono prima inizializzati su 1 . Ora che bacchetta[i] è stato scelto come primo bacchette. bacchetta[i] E bacchette[(i+1)%5] sono soggetti alla prima operazione di attesa. Questi operazione di attesa delle bacchette indica che il filosofo li ha raccolti. Il processo del mangiare inizia quando il filosofo sceglie il suo bacchette . L'operazione di segnalazione viene ora eseguita su bacchette [i] E [(i+1)%5] una volta che il filosofo ha finito di mangiare. Il filosofo poi torna a dormire.

Per determinare se il sottothread si è unito o meno al thread principale, abbiamo utilizzato il file funzione pthread_join . Allo stesso modo, abbiamo verificato se il mutex lock è stato inizializzato utilizzando il file pthread_mutex_init metodo.

Per inizializzare e verificare se il nuovo thread è stato creato o meno, abbiamo utilizzato il file funzione pthread_create . In modo simile, abbiamo distrutto il blocco mutex usando il pthread_mutex_destroy funzione.

Il problema produttore-consumatore:

Un problema comune con la sincronizzazione dei processi multithreading è il problema produttore-consumatore . In esso sono presenti due processi: il primo è il processo del produttore , e il secondo è il processo del consumatore . Inoltre, si presuppone che entrambe le operazioni avvengano contemporaneamente in parallelo. Inoltre, sono un processo cooperativo, il che implica che condividono qualcosa tra loro. È importante che quando il buffer sia pieno , il produttore non può aggiungere dati. Quando il buffer è vuoto, il consumatore non può estrarre i dati dal buffer perché la dimensione del buffer comune tra produttore e consumatore lo è fisso . La questione è posta in questo modo. Quindi, per implementare il problema Produttore-Consumatore e risolverlo, utilizzeremo l’idea della programmazione parallela.

Esempio:

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

Produzione:

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

Spiegazione:

Eseguiamo due compiti. Le funzioni consumatore() E produttore() indicare lo stato e il funzionamento del consumatore E produttore . IL metodo produttore() creerà il blocco mutex e determinare se il buffer lo è pieno quando viene chiamato. Quando il buffer è pieno, non verrà prodotto nulla. In caso contrario, lo farà creare , e poi, dopo il produzione , si metterà in modalità di sospensione per sbloccare il file blocco mutex . Come il produttore , il consumatore crea prima il blocco mutex , controlla il respingente , consuma il Prodotto , quindi rilascia il blocco prima di tornare a dormire.

UN contatore (x) verrà utilizzato durante la produzione e continuerà a crescere finché il produttore non produrrà l'articolo. Tuttavia, il consumatore produrrà meno dello stesso prodotto articolo (x) .

Conclusione:

L'idea di usare due O più thread per eseguire un programma è noto come multithreading nel linguaggio di programmazione C. Multithreading consente l'esecuzione simultanea di più attività. Il componente eseguibile più semplice di un programma è a filo . Il processo è l'idea che un compito può essere completato suddividendolo in più compiti più piccoli sottoprocessi .

Il file di intestazione pthread.h è necessario per implementare il multithreading in C poiché non può essere eseguito direttamente.