2010-10-11 9 views
28

Tengo una aplicación de procesamiento de números escrita en C. Es un tipo de bucle principal que para cada valor llama, para aumentar los valores de "i", una función que realiza algunos cálculos. Leí sobre el multihilo, y estoy considerando aprender un poco sobre él, en C. Me pregunto si de alguna manera el código general como el mío podría ser multiproceso automático y cómo.Cómo "multiprocesar" el código C

Gracias

P.D. Para tener una idea acerca de mi código, digamos que es algo como esto:

main(...) 
for(i=0;i<=ntimes;i++)get_result(x[i],y[i],result[i]); 

...

void get_result(float x,float y,float result){ 
    result=sqrt(log (x) + log (y) + cos (exp (x + y)); 
(and some more similar mathematical operations) 
} 
+2

¿Qué sistema operativo ya que la mayoría de las funciones de roscado dependen del sistema – rerun

+0

el sistema operativo que uso es Linux – flow

+1

No es exactamente lo que han pedido, pero que podría estar interesado en esto: http: //www.cs.utk.edu/~plank/plank/classes/cs360/360/notes/Setjmp/lecture.html. Busque la sección "Subprocesos múltiples del pobre". – Artium

Respuesta

17

Una alternativa a multihilo su código estaría utilizando pthreads (proporciona más precisa control que OpenMP).

Suponiendo x, y & result son matrices de variables globales,

#include <pthread.h> 

... 

void *get_result(void *param) // param is a dummy pointer 
{ 
... 
} 

int main() 
{ 
... 
pthread_t *tid = malloc(ntimes * sizeof(pthread_t)); 

for(i=0; i<ntimes; i++) 
    pthread_create(&tid[i], NULL, get_result, NULL); 

... // do some tasks unrelated to result  

for(i=0; i<ntimes; i++) 
    pthread_join(tid[i], NULL); 
... 
} 

(compilar el código con gcc prog.c -lpthread)

+1

esto no se escalará en una aplicación grande, ya que de hecho perderá el control de la cantidad de subprocesos que se están ejecutando; un subproceso por tarea dará como resultado el agotamiento de los recursos del sistema operativo. Además, no tiene sentido tener 3k hilos cuando solo tienes ~ 8-32 núcleos de CPU – paulm

+0

¿Qué es 'ntimes'? ¿Algún valor definido en algunos de los "' ... '" en su código? – HelloGoodbye

26

Si la tarea es altamente paralelizable y su compilador es moderno, podría intentar OpenMP . http://en.wikipedia.org/wiki/OpenMP

+0

+1 Me pegó. OpenMP es perfecto para el tipo de cosas que describe el OP. – casablanca

+0

sí. lo que me pregunto es si habrá una sobrecarga al usar multiproceso en lugar de solo hacer el ciclo principal de "fuerza bruta"; Quiero decir, si generalmente se demuestra que en casos como este, multithread supera los cálculos en serie, incluso si debe haber algún tipo de control para los hilos – flow

+0

@Werner: Eso depende en gran medida del problema que está resolviendo y la implementación de los algoritmos. Cuantas más cosas se pueden hacer completamente independientes del resto, mejor se presta a la ejecución paralela. –

3

Dependiendo del sistema operativo, puede usar los hilos posix. En su lugar, podría implementar multiprocesamiento sin pila utilizando máquinas de estado. Hay un libro realmente bueno titulado "multitarea integrada" por Keith E. Curtis. Es solo un conjunto cuidadosamente elaborado de declaraciones de mayúsculas y minúsculas. Funciona muy bien, lo he usado en todo, desde Apple Mac, semiconductor de conejo, AVR, PC.

Vali

+0

¿Cuál sería el sentido de "multithreading" (los co-states no son subprocesos) un proceso de cálculo en un modelo donde podría _NEVER_ tener verdadera concurrencia? –

+1

Las máquinas de estado verdadero no usan conmutadores de contexto y no son subprocesos "reales". El autor no indicó qué SO o plataforma en el momento que comenté. Si se trata simplemente de una cuestión de capacidad de respuesta del programa, las máquinas de estado pueden ser una buena solución. Ciertamente más fácil de depurar. El bloqueo es un problema. – ValiRossi

9

Si usted está esperando para proporcionar la concurrencia de un solo bucle por algún tipo de computación científica o similares, como dice OpenMP @Novikov realmente es la mejor opción; esto es para lo que fue diseñado.

Si está buscando aprender el enfoque más clásico que normalmente vería en una aplicación escrita en C ... En POSIX, quiere pthread_create() y otros. No estoy seguro de cuál podría ser tu fondo con la simultaneidad en otros idiomas, pero antes de profundizar en eso, querrás conocer bastante bien tus primitivas de sincronización (mutexes, semáforos, etc.) y comprender cuándo lo harás. necesito usarlos Ese tema podría ser un libro completo o un conjunto de preguntas de SO en sí mismo.

8

Debería echarle un vistazo a openMP para esto. El C/C++ ejemplo en esta página es similar a su código: https://computing.llnl.gov/tutorials/openMP/#SECTIONS

#include <omp.h> 
#define N  1000 

main() 
{ 

int i; 
float a[N], b[N], c[N], d[N]; 

/* Some initializations */ 
for (i=0; i < N; i++) { 
    a[i] = i * 1.5; 
    b[i] = i + 22.35; 
    } 

#pragma omp parallel shared(a,b,c,d) private(i) 
    { 

    #pragma omp sections nowait 
    { 

    #pragma omp section 
    for (i=0; i < N; i++) 
     c[i] = a[i] + b[i]; 

    #pragma omp section 
    for (i=0; i < N; i++) 
     d[i] = a[i] * b[i]; 

    } /* end of sections */ 

    } /* end of parallel section */ 

} 

Si prefiere no utilizar OpenMP se podría utilizar cualquiera de pthreads o clon/esperar directamente.

Independientemente de la ruta que elijas, simplemente estás dividiendo tus matrices en fragmentos que procesará cada subproceso. Si todo su procesamiento es puramente computacional (como lo sugiere su función de ejemplo), entonces debería hacer bien en tener solo tantos hilos como procesadores lógicos.

Hay algunos gastos indirectos con la adición de subprocesos para hacer el procesamiento paralelo, así que asegúrese de que le da a cada hilo el trabajo suficiente para compensarlo. Por lo general lo harás, pero si cada hilo solo termina con 1 cálculo para hacer y los cálculos no son tan difíciles de hacer, entonces en realidad puedes desacelerar las cosas. Siempre puede tener menos hilos que procesadores si ese es el caso.

Si tiene algo de IO pasando en su trabajo, entonces puede encontrar que tener más hilos que procesadores es una ganancia porque mientras que un hilo puede estar bloqueando la espera de que un IO complete otro hilo puede hacer sus cálculos. Sin embargo, debe tener cuidado al hacer IO en el mismo archivo en hilos.

3

un buen ejercicio para aprender programación concurrente en cualquier idioma sería trabajar en una implementación de grupo de subprocesos.
En este patrón, crea algunos hilos por adelantado. Esos hilos se tratan como un recurso. Un objeto/estructura de grupo de subprocesos se usa para asignar tareas definidas por el usuario a esos subprocesos para su ejecución. Cuando la tarea finaliza, puedes recopilar sus resultados. Puede usar el grupo de subprocesos como un patrón de diseño de propósito general para la concurrencia. La idea principal podría ser similar a

#define number_of_threads_to_be_created 42 
// create some user defined tasks 
Tasks_list_t* task_list_elem = CreateTasks(); 
// Create the thread pool with 42 tasks 
Thpool_handle_t* pool = Create_pool(number_of_threads_to_be_created); 

// populate the thread pool with tasks 
for (; task_list_elem; task_list_elem = task_list_elem->next) { 
    add_a_task_to_thpool (task_list_elem, pool); 
} 
// kick start the thread pool 
thpool_run (pool); 

// Now decide on the mechanism for collecting the results from tasks list. 
// Some of the candidates are: 
// 1. sleep till all is done (naive) 
// 2. pool the tasks in the list for some state variable describing that the task has 
// finished. This can work quite well in some situations 
// 3. Implement signal/callback mechanism that a task can use to signal that it has 
// finished executing. 

El mecanismo de recopilación de datos de tareas y la cantidad de hilos utilizados en la piscina debe ser elegido para reflejar sus necesidades y las capacidades del entorno de hardware y tiempo de ejecución.
También tenga en cuenta que este patrón no dice nada sobre cómo debe "sincronizar" sus tareas entre sí o con el entorno exterior. También el manejo de errores puede ser un poco complicado (ejemplo: qué hacer cuando falla una tarea). Esos dos aspectos deben pensarse de antemano: pueden restringir el uso del patrón del grupo de subprocesos.

Sobre grupo de subprocesos:
http://en.wikipedia.org/wiki/Thread_pool_pattern
http://docs.oracle.com/cd/E19253-01/816-5137/ggedn/index.html

Una buena literatura sobre pthreads para ponerse en marcha:
http://www.advancedlinuxprogramming.com/alp-folder/alp-ch04-threads.pdf

2

para abordar específicamente el "automáticamente multiproceso" parte de la pregunta del OP:

Una vista realmente interesante de cómo programar el paralelismo fue des igned en un lenguaje llamado Cilk Plus inventado por MIT y ahora propiedad de Intel. Para citar a Wikipedia, la idea es que

"el programador debe ser responsable para exponer el paralelismo, elementos de identificación que puede de manera segura ser ejecutadas en paralelo, sino que debe entonces a la carrera en tiempo entorno, particularmente el planificador , para decidir durante la ejecución cómo dividir realmente el trabajo entre procesadores. "

Cilk Plus es un superconjunto de C++ estándar. Solo contiene algunas palabras clave adicionales (_Cilk_spawn, _Cilk_sync y _Cilk_for) que permiten al programador etiquetar partes de su programa como paralelizables.El programador no requiere mandato que cualquier código se ejecute en un nuevo hilo, solo permite el programador de tiempo de ejecución liviano para engendrar un nuevo hilo si y solo si es realmente lo correcto en condiciones de tiempo de ejecución particulares.

Para utilizar Cilk Plus, sólo tiene que añadir sus palabras clave en su código, y construir con Intel's C++ compiler.

1

El código no es automática multi-hilo por el compilador si ese era su pregunta. Tenga en cuenta que los propios estándares C no saben nada sobre multi-threading, ya que si puede usar multi-threading o no depende del idioma que usa para la codificación, sino de la plataforma de destino que está codificando. El código escrito en C puede ejecutarse en prácticamente cualquier cosa para la que exista un compilador de C. Incluso existe un compilador de C para una computadora C64 (casi completamente compatible con ISO-99); sin embargo, para admitir varios subprocesos, la plataforma debe tener un sistema operativo que lo soporte y generalmente esto significa que debe haber al menos cierta funcionalidad de CPU. Un sistema operativo puede hacer subprocesos casi exclusivamente en software, esto será muy lento y no habrá protección de memoria, pero es posible, sin embargo, incluso en ese caso, necesita al menos interrupciones programables.

Así cómo escribir código multihilo C depende por completo en el sistema operativo de la plataforma de destino. Existen sistemas conformes POSIX (OS X, FreeBSD, Linux, etc.) y sistemas que tienen su propia biblioteca para eso (Windows). Algunos sistemas tienen más de biblioteca para ello (por ejemplo, OS X tiene la biblioteca POSIX, pero también es el gestor de hilo de carbono se puede utilizar en C (aunque creo que es más bien legado hoy en día).

Por supuesto existe cruz bibliotecas de hebras -platform y algunos compiladores modernos tienen soporte para cosas como OpenMP, donde el compilador generará automáticamente el código para crear los hilos en su plataforma de destino elegido, pero no muchos compiladores apoyan y los que lo hacen apoyar por lo general no se incluyen completa. por lo general, se obtiene el apoyo del sistema más amplio mediante el uso de los hilos POSIX, más a menudo llamados "pthreads". la única plataforma importante no apoyar es Windows y aquí se pueden utilizar las bibliotecas 3 ª parte libres como this one. Varios otros puertos existe también (Cygwin tiene uno seguro). Si algún día tendrá una UI, tal vez desee o use una biblioteca multiplataforma como wxWidgets o SDL, ambas ofrecen soporte consistente de múltiples subprocesos en todas las plataformas compatibles.

1

Si una iteración de bucle es independiente de los anteriores, entonces no es un enfoque muy simple: tratar de procesamiento múltiple, en lugar de multi-threading.

Digamos que tiene 2 núcleos y ntimes es 100, luego 100/2 = 50, así que cree 2 versiones del programa donde la primera itera de 0 a 49, la otra de 50 a 99. Ejecútelas ambas, sus núcleos debe mantenerse bastante ocupado.

Este es un enfoque muy simplista, sin embargo, usted no tiene que meterse con la creación del hilo, sincronización, etc.

+0

Los dos procesos deben ejecutarse durante al menos uno o dos minutos para compensar el costo de iniciar un nuevo proceso a través de fork(). Dicho esto, utilizo fork() para el procesamiento por lotes cuando cada tarea simultánea es de larga duración. –

3

C++ compilador de Intel es realmente capaz de paralellizing automáticamente su código. Es solo un cambio de compilador que necesita habilitar. Sin embargo, no funciona tan bien como OpenMP (es decir, no siempre tiene éxito o el programa resultante es más lento). Desde el sitio web de Intel:. "auto-paralelización, que se activa por el -paralelo (Linux OS y Mac OS * X) o/Qparallel (Windows * OS) opción, identifica automáticamente las estructuras de bucle que contienen paralelismo Durante la compilación, el compilador intenta automáticamente deconstruir las secuencias de código en hilos separados para el procesamiento paralelo. No se necesita ningún otro esfuerzo por parte del programador ".

1

Puede utilizar pthreads para realizar múltiples hilos en C. aquí hay un ejemplo simple basado en pthreads.

#include<pthread.h> 
#include<stdio.h> 

void *mythread1(); //thread prototype 
void *mythread2(); 

int main(){ 
    pthread_t thread[2]; 
    //starting the thread 
    pthread_create(&thread[0],NULL,mythread1,NULL); 
    pthread_create(&thread[1],NULL,mythread2,NULL); 
    //waiting for completion 
    pthread_join(thread[0],NULL); 
    pthread_join(thread[1],NULL); 


    return 0; 
} 

//thread definition 
void *mythread1(){ 
    int i; 
    for(i=0;i<5;i++) 
     printf("Thread 1 Running\n"); 
} 
void *mythread2(){ 
    int i; 
    for(i=0;i<5;i++) 
     printf("Thread 2 Running\n"); 
} 

Referencia: C program to implement Multithreading-Multithreading in C

Cuestiones relacionadas