C ++ multiproceso
El subproceso múltiple es una forma especializada de multitarea y una multitarea es la característica que le permite a su computadora ejecutar dos o más programas al mismo tiempo. En general, hay dos tipos de multitarea: basada en procesos y basada en subprocesos.
La multitarea basada en procesos maneja la ejecución concurrente de programas. La multitarea basada en subprocesos se ocupa de la ejecución simultánea de partes del mismo programa.
Un programa multiproceso contiene dos o más partes que pueden ejecutarse simultáneamente. Cada parte de dicho programa se denomina hilo y cada hilo define una ruta de ejecución separada.
C ++ no contiene ningún soporte integrado para aplicaciones multiproceso. En cambio, depende completamente del sistema operativo para proporcionar esta función.
Este tutorial asume que está trabajando en el sistema operativo Linux y vamos a escribir un programa C ++ multiproceso usando POSIX. POSIX Threads, o Pthreads, proporciona API que están disponibles en muchos sistemas POSIX similares a Unix, como FreeBSD, NetBSD, GNU / Linux, Mac OS X y Solaris.
Crear hilos
La siguiente rutina se utiliza para crear un hilo POSIX:
#include <pthread.h>
pthread_create (thread, attr, start_routine, arg)
Aquí, pthread_createcrea un nuevo hilo y lo hace ejecutable. Esta rutina se puede llamar cualquier número de veces desde cualquier lugar dentro de su código. Aquí está la descripción de los parámetros:
No Señor | Descripción de parámetros |
---|---|
1 | thread Un identificador único y opaco para el nuevo hilo devuelto por la subrutina. |
2 | attr Objeto de atributo opaco que se puede utilizar para establecer atributos de hilo. Puede especificar un objeto de atributos de hilo o NULL para los valores predeterminados. |
3 | start_routine La rutina de C ++ que ejecutará el hilo una vez que se cree. |
4 | arg Un único argumento que se puede pasar a start_routine. Debe pasarse por referencia como una conversión de puntero de tipo void. Se puede usar NULL si no se va a pasar ningún argumento. |
El número máximo de subprocesos que puede crear un proceso depende de la implementación. Una vez creados, los hilos son iguales y pueden crear otros hilos. No existe una jerarquía o dependencia implícita entre los subprocesos.
Terminación de hilos
Existe la siguiente rutina que usamos para terminar un hilo POSIX:
#include <pthread.h>
pthread_exit (status)
aquí pthread_exitse utiliza para salir explícitamente de un hilo. Normalmente, la rutina pthread_exit () se llama después de que un hilo ha completado su trabajo y ya no es necesario que exista.
Si main () termina antes que los subprocesos que ha creado y sale con pthread_exit (), los otros subprocesos continuarán ejecutándose. De lo contrario, se cerrarán automáticamente cuando main () finalice.
Example
Este código de ejemplo simple crea 5 hilos con la rutina pthread_create (). Cada hilo imprime un "¡Hola mundo!" message, y luego termina con una llamada a pthread_exit ().
#include <iostream>
#include <cstdlib>
#include <pthread.h>
using namespace std;
#define NUM_THREADS 5
void *PrintHello(void *threadid) {
long tid;
tid = (long)threadid;
cout << "Hello World! Thread ID, " << tid << endl;
pthread_exit(NULL);
}
int main () {
pthread_t threads[NUM_THREADS];
int rc;
int i;
for( i = 0; i < NUM_THREADS; i++ ) {
cout << "main() : creating thread, " << i << endl;
rc = pthread_create(&threads[i], NULL, PrintHello, (void *)i);
if (rc) {
cout << "Error:unable to create thread," << rc << endl;
exit(-1);
}
}
pthread_exit(NULL);
}
Compile el siguiente programa usando la biblioteca -lpthread de la siguiente manera:
$gcc test.cpp -lpthread
Ahora, ejecute su programa que da la siguiente salida:
main() : creating thread, 0
main() : creating thread, 1
main() : creating thread, 2
main() : creating thread, 3
main() : creating thread, 4
Hello World! Thread ID, 0
Hello World! Thread ID, 1
Hello World! Thread ID, 2
Hello World! Thread ID, 3
Hello World! Thread ID, 4
Pasar argumentos a hilos
Este ejemplo muestra cómo pasar varios argumentos a través de una estructura. Puede pasar cualquier tipo de datos en una devolución de llamada de hilo porque apunta a vacío como se explica en el siguiente ejemplo:
#include <iostream>
#include <cstdlib>
#include <pthread.h>
using namespace std;
#define NUM_THREADS 5
struct thread_data {
int thread_id;
char *message;
};
void *PrintHello(void *threadarg) {
struct thread_data *my_data;
my_data = (struct thread_data *) threadarg;
cout << "Thread ID : " << my_data->thread_id ;
cout << " Message : " << my_data->message << endl;
pthread_exit(NULL);
}
int main () {
pthread_t threads[NUM_THREADS];
struct thread_data td[NUM_THREADS];
int rc;
int i;
for( i = 0; i < NUM_THREADS; i++ ) {
cout <<"main() : creating thread, " << i << endl;
td[i].thread_id = i;
td[i].message = "This is message";
rc = pthread_create(&threads[i], NULL, PrintHello, (void *)&td[i]);
if (rc) {
cout << "Error:unable to create thread," << rc << endl;
exit(-1);
}
}
pthread_exit(NULL);
}
Cuando se compila y ejecuta el código anterior, produce el siguiente resultado:
main() : creating thread, 0
main() : creating thread, 1
main() : creating thread, 2
main() : creating thread, 3
main() : creating thread, 4
Thread ID : 3 Message : This is message
Thread ID : 2 Message : This is message
Thread ID : 0 Message : This is message
Thread ID : 1 Message : This is message
Thread ID : 4 Message : This is message
Unir y separar hilos
Hay dos rutinas siguientes que podemos usar para unir o separar hilos:
pthread_join (threadid, status)
pthread_detach (threadid)
La subrutina pthread_join () bloquea el hilo de llamada hasta que el hilo 'threadid' especificado termina. Cuando se crea un hilo, uno de sus atributos define si se puede unir o desconectar. Solo se pueden unir los subprocesos que se crean como unibles. Si un hilo se crea como separado, nunca podrá unirse.
Este ejemplo demuestra cómo esperar a que se completen los subprocesos utilizando la rutina de unión Pthread.
#include <iostream>
#include <cstdlib>
#include <pthread.h>
#include <unistd.h>
using namespace std;
#define NUM_THREADS 5
void *wait(void *t) {
int i;
long tid;
tid = (long)t;
sleep(1);
cout << "Sleeping in thread " << endl;
cout << "Thread with id : " << tid << " ...exiting " << endl;
pthread_exit(NULL);
}
int main () {
int rc;
int i;
pthread_t threads[NUM_THREADS];
pthread_attr_t attr;
void *status;
// Initialize and set thread joinable
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
for( i = 0; i < NUM_THREADS; i++ ) {
cout << "main() : creating thread, " << i << endl;
rc = pthread_create(&threads[i], &attr, wait, (void *)i );
if (rc) {
cout << "Error:unable to create thread," << rc << endl;
exit(-1);
}
}
// free attribute and wait for the other threads
pthread_attr_destroy(&attr);
for( i = 0; i < NUM_THREADS; i++ ) {
rc = pthread_join(threads[i], &status);
if (rc) {
cout << "Error:unable to join," << rc << endl;
exit(-1);
}
cout << "Main: completed thread id :" << i ;
cout << " exiting with status :" << status << endl;
}
cout << "Main: program exiting." << endl;
pthread_exit(NULL);
}
Cuando se compila y ejecuta el código anterior, produce el siguiente resultado:
main() : creating thread, 0
main() : creating thread, 1
main() : creating thread, 2
main() : creating thread, 3
main() : creating thread, 4
Sleeping in thread
Thread with id : 0 .... exiting
Sleeping in thread
Thread with id : 1 .... exiting
Sleeping in thread
Thread with id : 2 .... exiting
Sleeping in thread
Thread with id : 3 .... exiting
Sleeping in thread
Thread with id : 4 .... exiting
Main: completed thread id :0 exiting with status :0
Main: completed thread id :1 exiting with status :0
Main: completed thread id :2 exiting with status :0
Main: completed thread id :3 exiting with status :0
Main: completed thread id :4 exiting with status :0
Main: program exiting.