logo

MULTIHILO EN C

Introducción:

En C, el término 'multiproceso' describe el uso de numerosos hilos al mismo tiempo. Cada hilo hace un tarea diferente . Debido a la naturaleza concurrente del subproceso múltiple, se pueden realizar muchas tareas a la vez. Además, subprocesos múltiples reduce el Uso de recursos de la CPU . Hay dos categorías de multitarea: basado en procesos y basado en hilos . Cuando algo se describe como subprocesos múltiples, significa que al menos dos o quizás más subprocesos se están ejecutando en el mismo proceso a la vez. Primero debemos entender qué son un subproceso y un proceso para poder comprender el subproceso múltiple en C. Veamos estos temas para obtener una mejor comprensión.

llave ins

¿Qué son los procesos y los hilos?

A hilo es el edificio fundamental bloquear de la ejecución de cualquier proceso. Un programa se compone de varios procesos y cada proceso se compone de subprocesos, que son unidades mucho más básicas. Por lo tanto, el subproceso puede considerarse el bloque de construcción fundamental de un proceso o la unidad más simple que determina conjuntamente la utilización de la CPU.

Los siguientes elementos están incluidos en un hilo:

ID del hilo:

es un especial ID del hilo que se genera en el momento de la formación del hilo y se retiene durante la duración de ese hilo específico.

Contador de programa:

Es un valor que el cargas de hardware .

Un conjunto registrado:

Es una colección de registros comunes .

Un montón:

Es un remanente de eso hilo específico .

Además, si dos hilos trabajan simultáneamente en el mismo proceso, comparten código , secciones de datos y otros recursos del sistema operativo como archivos abre y señales . Un proceso pesado, un tipo de proceso convencional, puede controlar un hilo. Sin embargo, un control multiproceso tiene la capacidad de abrir y realizar múltiples tareas al mismo tiempo. El sistema se vuelve considerablemente más efectivo como resultado del uso de hilos, razón por la cual son útiles.

La distinción entre soltero y subprocesos múltiples en C se explica. En primer lugar, es un proceso de un solo hilo . Como resultado, todo el bloque -incluido el código, datos, etc.-se considera como un proceso, y ese proceso solo tiene un hilo. Significa que esta técnica completará sólo una tarea a la vez. Pero hay un proceso de subprocesos múltiples que se opone a esto. Hay actividades como código, pila, datos , y archivos también, pero los realizan varios subprocesos, cada uno de los cuales tiene su propia pila y registros. Dado que en esta situación se pueden completar numerosas tareas a la vez, el proceso se conoce como proceso de subprocesos múltiples .

El hilo viene en dos variedades:

Hilo a nivel de usuario:

Está a nivel de usuario, como su nombre lo indica. El kernel no tiene acceso a sus datos.

Hilo a nivel del kernel

El tipo de hilo se refiere a la relación del hilo con el núcleo y el sistema operativo del sistema.

Proceso- La serie de pasos que se siguen para llevar a cabo un programa se puede denominar proceso . Un programa no se ejecuta inmediatamente cuando se ejecuta. Se divide en algunos pasos básicos que se llevan a cabo secuencialmente de manera organizada para eventualmente conducir a la ejecución de un proceso.

Un proceso que se ha dividido en pasos más pequeños se denomina 'proceso clon o hijo', mientras que el proceso original se conoce como el proceso 'padre' . En la memoria, cada proceso utiliza una cierta cantidad de espacio que no se comparte con ningún otro proceso.

Un procedimiento pasa por algunas etapas antes de su ejecución.

NUEVO-

En esta situación, se inicia un nuevo proceso. generado .

LISTO-

Cuando un proceso está preparado y esperando que se le asigne un procesador, se encuentra en este estado.

CORRER-

Cuando el proceso está activo, es el estado.

ESPERA-

saltar lista

Cuando un proceso está en este estado, algo está espera que suceda.

TERMINADO-

creación de instancias en java

Es el estado en el que se está realizando el trámite.

¿Por qué C es multiproceso?

subprocesos múltiples en la idea C se puede aprovechar a través del paralelismo para mejorar una funcionalidad de la aplicación . Considere el caso en el que tiene varias pestañas abiertas en una ventana del navegador. Luego, cada pestaña funciona simultáneamente y podría denominarse Hilo . Suponiendo que usemos Microsoft Excel , un hilo se encargará formato de texto , y un hilo manejar la entrada . Por lo tanto, la característica de subprocesos múltiples de C simplifica la realización de múltiples tareas a la vez. La creación de un hilo es considerablemente más rápida. La transferencia de contexto entre hilos ocurre más rápidamente. Además, la comunicación entre subprocesos se puede realizar más rápidamente y la terminación de subprocesos es sencilla.

¿Cómo escribir programas en C para subprocesos múltiples?

Aunque las aplicaciones multiproceso no están integradas en el lenguaje C, es posible según el sistema operativo. El biblioteca estándar threads.h se utiliza para implementar la idea de subprocesos múltiples en C . Sin embargo, actualmente no existe ningún compilador que pueda hacer esto. Debemos emplear implementaciones específicas de plataforma, como la 'POSIX' biblioteca de subprocesos, utilizando el archivo de encabezado pthread.h , si queremos utilizar subprocesos múltiples en C. 'Philos' es otro nombre para esto. A POSIX El hilo se puede crear de las siguientes maneras:

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

En este caso, Pthread_create crea un nuevo hilo para que el hilo sea ejecutable. Le permite implementar subprocesos múltiples en C tantas veces como desee en su código. Los parámetros y sus descripciones anteriores se enumeran aquí.

hilo:

Es un identificación singular que el devoluciones del subproceso .

atributo:

Cuando queremos establecer atributos de hilo, usamos esto atributo opaco .

rutina_inicio:

Cuando rutina_inicio Se genera, el hilo ejecutará una rutina.

argumento:

El parámetro que el rutina_inicio recibe. NULO se utilizará si no se dan argumentos.

Ciertos ejemplos de subprocesos múltiples en C

A continuación se muestran algunos ejemplos de problemas de subprocesos múltiples en C.

1. La cuestión lector-escritor

Un problema común del sistema operativo con la sincronización de procesos es el problema lector/escritor . Supongamos que tenemos una base de datos que Lectores y Escritores , pueden acceder dos categorías de usuarios diferentes. Lectores son los únicos que pueden leer la base de datos, mientras que Escritores son los únicos que pueden leer la base de datos y actualizarla también. usemos IRCTC como un ejemplo sencillo. Si deseamos comprobar el estado de un determinado numero de tren , simplemente ingrese el número del tren en el sistema para ver la información pertinente del tren. Aquí solo se muestra la información que está presente en el sitio web. El operador de lectura es este. Sin embargo, si queremos reservar un billete, debemos rellenar el formulario de reserva de billetes con datos como nuestro nombre, edad, etc. Entonces, realizaremos una operación de escritura aquí. Se harán algunos ajustes a la Base de datos del IRCTC .

El problema es que varias personas están intentando acceder simultáneamente a la Base de datos del IRCTC . Podrían ser un escritor o un lector . El problema surge si un lector ya está utilizando la base de datos y un escritor accede a ella simultáneamente para trabajar con los mismos datos. Otro problema surge cuando un escritor utiliza una base de datos y un lector accede a la misma información que la base de datos. En tercer lugar, existe una dificultad cuando un escritor actualiza la base de datos mientras otro intenta actualizar datos en la misma base de datos. El cuarto escenario ocurre cuando dos lectores intentan recuperar el mismo material. Todos estos problemas surgen si el lector y el escritor utilizan los mismos datos de la base de datos.

El semáforo es un método que se emplea para resolver este problema. Veamos una ilustración de cómo utilizar este problema.

Proceso de lectura:

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

Explicación:

En este código, tenemos los datos de la variable compartida y el recuento de lectores rc . El condición equivocada La variable se utiliza para limitar el acceso a la proceso de escritura , y el exclusión mutua se utiliza para garantizar la exclusión mutua para acceder a los datos compartidos.

El proceso de lectura está representado por el función lector() . El recuento de lectores (rc) se incrementa antes de alcanzar el bloqueo mutex . Usa pthread_cond_wait() esperar en el condición equivocada variable si es el primer lector (rc == 1) . Como resultado, se impedirá que los escritores escriban hasta que todos los lectores hayan terminado.

El proceso lector comprueba si fue el último lector (rc == 0) y baja al lector contar (rc--) después de leer los datos compartidos. Si era, pthread_cond_signal() señala el condición equivocada variable para permitir que continúen los procesos de escritura en espera.

Utilizando el pthread_create() y Funciones pthread_join() , nosotros nuevo y unirse múltiples hilos de lectura en el función principal . Se asigna una identificación individual a cada hilo de lector con fines de identificación.

Proceso del escritor:

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

En el ejemplo anterior, igual que el proceso de lectura , se lleva a cabo una operación conocida como operación de espera en 'wrt' cuando un usuario desea acceder al dato u objeto. Después de eso, el nuevo usuario no podrá acceder al objeto. Y una vez que el usuario ha terminado de escribir, se realiza otra operación de señal en wrt .

2. problema de bloqueo y desbloqueo:

la idea de un exclusión mutua se utiliza en subprocesos múltiples en C para garantizar que no habrá un condición de carrera Entre los hilos . Cuando varios subprocesos comienzan a procesar los mismos datos a la vez, esta circunstancia se conoce como carreras . Sin embargo, si estas circunstancias existen, debemos hacerlo. Usamos el bloqueo de mutex () y funciones de desbloqueo () para asegurar una sección particular de código para un hilo específico. De modo que otro hilo no puede comenzar a realizar la misma operación. El 'sección/región crítica' es el nombre dado a esta área de código protegida. Antes de utilizar los recursos compartidos, configuramos un lote en una zona determinada y, una vez que terminamos de usarlos, los desbloqueamos una vez más.

Examinemos el funcionamiento del mutex para bloquear y desbloquear en subprocesos múltiples en C:

Ejemplo:

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

Explicación:

tipo de retorno en java

En este ejemplo anterior, explicamos cómo cerrar y desbloquear una determinada región de código que nos protege de la situación de las carreras. 'pthread_mutex_t' se utiliza como un inicializador en el ejemplo anterior. 'pthread_mutex_lock' es entonces escrito antes del comienzo del código que queremos bloquear. La codificación que deseamos bloquear finaliza después de eso. Después de eso, el bloqueo del código finaliza usando 'pthread_mutex_unlock' ; De ahora en adelante, ningún código estará en modo de bloqueo.

El problema del filósofo del comedor:

Uno de los problemas clásicos con la sincronización es el cuestión del filósofo gastronómico . Se requiere una asignación simple de recursos para varios procesos, pero no debería resultar en una estancamiento o hambre . El problema del filósofo gastronómico Puede verse como una representación sencilla de una serie de procesos, cada uno de los cuales exige recursos. Dado que cada uno de estos procesos requiere una asignación de recursos, es necesario distribuir esos recursos entre todos los procesos para que ningún proceso se atasque o deje de funcionar.

Supongamos que hay cinco filósofos sentados en una mesa en forma de círculo . En un momento comen y en otro reflexionan sobre algo. Alrededor de la mesa redonda, los filósofos están distribuidos uniformemente en las sillas. Además, en el centro de la mesa hay un plato de arroz y cinco palillos para cada filósofo. Cuando la filósofa siente que no puede interactuar con sus colegas que están sentados cerca.

De vez en cuando, una filósofa toma dos palillos cuando tiene hambre. Ella elige dos palillos de sus vecinos, uno en su izquierda y uno sobre ella bien -que estén al alcance de la mano. Pero el filósofo nunca debería coger más de un palillo a la vez. Obviamente no podrá recoger el palillo que está usando el vecino.

Ejemplo:

Usemos un ejemplo para demostrar cómo se implementa esto en 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;>

Explicación:

Palillos se puede representar mediante un semáforo. Puesto que hay palillos sobre la mesa y ningún filósofo ha elegido uno, todos los componentes de los palillos se inicializan primero para 1 . Ahora eso palillo [yo] ha sido elegido como el primero palillo. palillo [yo] y palillo[(i+1)%5] están sujetos a la primera operación de espera. Estos operación de espera de los palillos indica que el filósofo los ha recogido. El proceso de comer comienza una vez que el filósofo selecciona su palillo . La operación de señal ahora se lleva a cabo en el palillos [yo] y [(i+1)%5] una vez que el filósofo ha terminado de comer. Luego el filósofo se vuelve a dormir.

cadena comparable

Para determinar si el subproceso se ha unido al hilo principal o no, utilizamos el función pthread_join . Del mismo modo, hemos comprobado si el exclusión mutua El bloqueo se ha inicializado utilizando el pthread_mutex_init método.

Para inicializar y verificar si el nuevo hilo se creó o no, utilizamos el función pthread_create . De manera similar, destruimos el bloqueo mutex utilizando el pthread_mutex_destroy función.

El problema productor-consumidor:

Un problema común con la sincronización de procesos multiproceso es el problema productor-consumidor . En él están presentes dos procesos: el primero es el proceso del productor , y el segundo es el proceso del consumidor . Además, se supone que ambas operaciones se producen simultáneamente y en paralelo. Además, son un proceso cooperativo, lo que implica que comparten algo entre sí. Es importante que cuando el buffer esté lleno , el productor no puede agregar datos. Cuando el búfer está vacío, el consumidor no puede extraer datos del búfer porque el tamaño del búfer común entre el productor y el consumidor es fijado . La cuestión está planteada de esta manera. Por lo tanto, para implementar el problema Productor-Consumidor y resolverlo, emplearemos la idea de programación paralela.

Ejemplo:

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

Producción:

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

Explicación:

Realizamos dos tareas. Las funciones consumidor() y productor() indicar el estado y funcionamiento del consumidor y productor . El método productor() creará el bloqueo mutex y determinar si el buffer es lleno cuando se llama. Cuando el buffer esté lleno, no se producirá nada. Si no, lo hará crear , y luego, después del producción , se pondrá en modo de suspensión para desbloquear el bloqueo mutex . Como el productor , el consumidor primero crea el bloqueo mutex , comprueba el buffer , consume el producto y luego libera el bloqueo antes de volver a dormir.

A contador (x) se utilizará durante la fabricación y seguirá creciendo hasta que el fabricante produzca el artículo. Sin embargo, el consumidor fabricará menos productos de lo mismo. elemento (x) .

Conclusión:

La idea de utilizar dos o más hilos ejecutar un programa se conoce como subprocesos múltiples en el lenguaje de programación C. subprocesos múltiples Permite la ejecución simultánea de varias tareas. El componente ejecutable más simple de un programa es un hilo . El proceso es la idea de que una tarea se puede completar dividiéndola en varias tareas más pequeñas. subprocesos .

El archivo de encabezado pthread.h Es necesario para implementar subprocesos múltiples en C, ya que no se puede hacer directamente.