Pregunta

Uso de hilos POSIX & amp; C ++, tengo una operación "Insertar" que solo se puede hacer de forma segura uno a la vez.

Si tengo varios subprocesos en espera de insertar usando pthread_join, genero un nuevo subproceso cuando termina ¿Recibirán todos el hilo completo? señalice a la vez y genere múltiples inserciones o es seguro asumir que el hilo que recibe el "hilo completo" la señal generará un nuevo hilo bloqueando a los demás para que no creen nuevos hilos.

/* --- GLOBAL --- */
pthread_t insertThread;



/* --- DIFFERENT THREADS --- */
// Wait for Current insert to finish
pthread_join(insertThread, NULL); 

// Done start a new one
pthread_create(&insertThread, NULL, Insert, Data);

Gracias por las respuestas

El programa es básicamente una gran tabla hash que acepta solicitudes de clientes a través de Sockets.

Cada nueva conexión de cliente genera un nuevo hilo desde el cual puede realizar múltiples operaciones, específicamente búsquedas o inserciones. las búsquedas se pueden realizar en paralelo. Pero los insertos deben ser "combinados de nuevo" en un solo hilo. Se podría decir que las operaciones de búsqueda podrían realizarse sin generar un nuevo subproceso para el cliente, sin embargo, pueden demorar un tiempo y hacer que el servidor se bloquee, eliminando nuevas solicitudes. El diseño intenta minimizar las llamadas al sistema y la creación de subprocesos tanto como sea posible.

Pero ahora que sé que no es seguro la forma en que pensé que debería ser capaz de improvisar algo juntos

Gracias

¿Fue útil?

Solución

De opengroup.org en pthread_join :

  

Los resultados de múltiples llamadas simultáneas a pthread_join () que especifican el mismo hilo objetivo no están definidos.

Entonces, realmente no deberías tener varios hilos uniéndose a tu insertThread anterior.

Primero, al usar C ++, recomiendo boost. hilo . Se parecen al modelo POSIX de hilos, y también funcionan en Windows. Y le ayuda con C ++, es decir, haciendo que los objetos de función se puedan usar más fácilmente.

Segundo, ¿por qué quieres comenzar un nuevo hilo para insertar un elemento, cuando siempre tienes que esperar a que termine el anterior antes de comenzar el siguiente? Parece no ser el uso clásico de múltiples hilos.

Aunque ... Una solución clásica para esto sería tener un subproceso de trabajo obteniendo trabajos de una cola de eventos y otros subprocesos publicando la operación en la cola de eventos.

Si realmente solo quieres mantenerlo más o menos como lo tienes ahora, tendrías que hacer esto:

  • Cree una variable de condición, como insert_finished .
  • Todos los hilos que desean hacer una inserción, espere la variable de condición.
  • Tan pronto como se realiza un subproceso con su inserción, se activa la variable de condición.
  • Como la variable de condición requiere un mutex, puede notificar a todos los subprocesos en espera, todos quieren comenzar a insertar, pero como solo un subproceso puede adquirir el mutex a la vez, todos los subprocesos harán el insertar secuencialmente.

Pero debe tener cuidado de que su sincronización no se implemente de manera demasiado ad-hoc. Como esto se llama insert , sospecho que desea manipular una estructura de datos, por lo que probablemente desee implementar primero una estructura de datos segura para subprocesos, en lugar de compartir la sincronización entre los accesos de estructura de datos y todos los clientes También sospecho que habrá más operaciones que solo insert , que necesitará una sincronización adecuada ...

Otros consejos

De acuerdo con la especificación Single Unix: " Los resultados de múltiples llamadas simultáneas a pthread_join () que especifican el mismo hilo objetivo no están definidos. "

La " forma normal " de lograr un solo hilo para obtener la tarea sería configurar una variable de condición (no olvide el mutex relacionado): los hilos inactivos esperan en pthread_cond_wait () (o pthread_cond_timedwait ()), y cuando el hilo que hace el trabajo ha terminado , activa uno de los inactivos con pthread_cond_signal ().

Sí, como la mayoría de la gente recomienda, la mejor manera parece tener un hilo de trabajo que lee de una cola. Algunos fragmentos de código a continuación

    pthread_t       insertThread = NULL;
    pthread_mutex_t insertConditionNewMutex = PTHREAD_MUTEX_INITIALIZER;
    pthread_mutex_t insertConditionDoneMutex    = PTHREAD_MUTEX_INITIALIZER;
    pthread_cond_t  insertConditionNew      = PTHREAD_COND_INITIALIZER;
    pthread_cond_t  insertConditionDone     = PTHREAD_COND_INITIALIZER;

       //Thread for new incoming connection
        void * newBatchInsert()
        {
           for(each Word)
           {
                            //Push It into the queue
                            pthread_mutex_lock(&lexicon[newPendingWord->length - 1]->insertQueueMutex);
                                lexicon[newPendingWord->length - 1]->insertQueue.push(newPendingWord);
                            pthread_mutex_unlock(&lexicon[newPendingWord->length - 1]->insertQueueMutex);

           }

                    //Send signal to worker Thread
                    pthread_mutex_lock(&insertConditionNewMutex);
                        pthread_cond_signal(&insertConditionNew);
                    pthread_mutex_unlock(&insertConditionNewMutex);

                    //Wait Until it's finished
                    pthread_cond_wait(&insertConditionDone, &insertConditionDoneMutex);

        }


            //Worker thread
            void * insertWorker(void *)
            {

                while(1)        
                {

                    pthread_cond_wait(&insertConditionNew, &insertConditionNewMutex);

                    for (int ii = 0; ii < maxWordLength; ++ii)
                    {                   
                            while (!lexicon[ii]->insertQueue.empty())
                            {

                                queueNode * newPendingWord = lexicon[ii]->insertQueue.front();


                                lexicon[ii]->insert(newPendingWord->word);

                                pthread_mutex_lock(&lexicon[ii]->insertQueueMutex);
                                lexicon[ii]->insertQueue.pop();
                                pthread_mutex_unlock(&lexicon[ii]->insertQueueMutex);

                            }

                    }

                    //Send signal that it's done
                    pthread_mutex_lock(&insertConditionDoneMutex);
                        pthread_cond_broadcast(&insertConditionDone);
                    pthread_mutex_unlock(&insertConditionDoneMutex);

                }

            }

            int main(int argc, char * const argv[]) 
            {

                pthread_create(&insertThread, NULL, &insertWorker, NULL);


                lexiconServer = new server(serverPort, (void *) newBatchInsert);

                return 0;
            }

Los otros ya han señalado que esto tiene un comportamiento indefinido. Solo agregaría que la forma más simple de realizar su tarea (permitir que solo un hilo ejecute parte del código) es usar un mutex simple: necesita que los hilos que ejecutan ese código sean MUTally EXclusive, y ahí es donde llegó mutex su nombre :-)

Si necesita que el código se ejecute en un hilo específico (como Java AWT), entonces necesita variables condicionales. Sin embargo, debe pensar dos veces si esta solución realmente vale la pena. Imagínese cuántos cambios de contexto necesita si llama a su " operación de inserción " 10000 veces por segundo.

Como acabas de mencionar que estás usando una tabla hash con varias búsquedas paralelas a las inserciones, te recomiendo comprobar si puedes usar una tabla hash concurrente.

Como los resultados exactos de la búsqueda no son deterministas cuando inserta elementos simultáneamente, tal hash-map concurrente puede ser exactamente lo que necesita. Sin embargo, no he usado tablas hash concurrentes en C ++, pero como están disponibles en Java, seguramente encontrarás una biblioteca que hace esto en C ++.

La única biblioteca que encontré que admite inserciones sin bloquear nuevas búsquedas - Sunrise DD (y no estoy seguro de si admite inserciones concurrentes)

Sin embargo, el cambio del Mapa de Hash disperso de Google duplica el uso de la memoria. Las búsquedas deben realizarse con poca frecuencia, así que en lugar de intentar escribir mi propia biblioteca que combina las ventajas de ambos, preferiría bloquear la tabla suspendiendo búsquedas mientras los cambios se realizan de forma segura.

Gracias de nuevo

Me parece que desea serializar las inserciones en la tabla hash.

Para esto, desea un bloqueo, no generar nuevos hilos.

Según su descripción, parece muy ineficiente ya que está recreando el hilo de inserción cada vez que desea insertar algo. El costo de crear el hilo no es 0.

Una solución más común a este problema es generar un hilo de inserción que espera en una cola (es decir, se sienta en un bucle durmiendo mientras el bucle está vacío). Otros hilos luego agregan elementos de trabajo a la cola. El hilo de inserción selecciona los elementos de la cola en el orden en que se agregaron (o por prioridad si lo desea) y realiza la acción adecuada.

Todo lo que tiene que hacer es asegurarse de que la adición a la cola esté protegida de modo que solo un hilo a la vez tenga acceso para modificar la cola real, y que el hilo de inserción no haga una espera ocupada, sino que duerma cuando no hay nada en la cola (ver variable de condición).

Idealmente, no desea múltiples grupos de subprocesos en un solo proceso, incluso si realizan diferentes operaciones. La fiabilidad de un hilo es una definición arquitectónica importante, lo que lleva a crear pthread_join en un hilo principal si usa C.

Por supuesto, para un conjunto de subprocesos de C ++, también conocido como ThreadFactory, la idea es mantener abstractos los primitivos de subprocesos para que pueda manejar cualquier tipo de función / operación que se le pase.

Un ejemplo típico sería un servidor web que tendrá agrupaciones de conexiones y agrupaciones de subprocesos que atienden conexiones y luego las procesará más, pero todas se derivan de un proceso común de subprocesos.

RESUMEN: EVITE PTHREAD_JOIN EN cualquier lugar que no sea un hilo principal.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top