come creare un numero indefinito di thread e utilizzare WaitForMultipleObjects () in c su Windows

PS: Sono molto nuovo ai thread.

Ho un problema in cui ho bisogno di aspettare le richieste di connessione (numero arbitrario di volte) dai client, accettare una connessione su un socket, creare un thread di lavoro dopo la connessione. Il thread creato crea quindi un array di caratteri, funziona su di esso e deve passarlo al processo padre.

Sono stato in grado di creare i thread in un ciclo while come

while ((new_socket = accept(srv_sock, (struct sockaddr *)&client, &c)) != INVALID_SOCKET) { puts("\nConnection accepted"); _beginthreadex(0, 0, handle_client, &new_socket, 0, 0); } 

Ho visto che pthread_join() può essere usato per passare i dati da thread a processo padre (in unix). La mia domanda è, come posso integrarla in un ciclo nel processo principale. Mi aspetto che il seguente approccio comporterà una situazione in cui non è ansible stabilire più di una connessione tra client e server alla volta, cosa che non è desiderata.

  while ((new_socket = accept(srv_sock, (struct sockaddr *)&client, &c)) != INVALID_SOCKET) { puts("\nConnection accepted"); _beginthreadex(0, 0, handle_client, &new_socket, 0, 0); pthread_join(thread_id,&my_array); } 

EDIT: Sarei felice di sapere se quello che voglio è imansible o se ci sono alternative a pthread_join(). o le sue windows equivalenti.

EDIT: So che pthread_join() è per Unix e ho letto che WaitForMultipleObjects() è il suo equivalente per Windows. In ogni caso, non sono ancora riuscito a trovare una soluzione.

Ho visto che pthread_join () può essere usato per passare i dati dal thread al processo principale.

Non è del tutto corretto. Puoi passare un puntatore quando esci da un thread e raccogli quel puntatore usando pthread_join. Devi implementare tutta la logica da solo. L’API non sa (o cura) cosa sia il puntatore. I thread non hanno genitori e figli, sono fratelli.

Esempio per un creatore e un mietitore:

  • globale

     struct VarLengthArray { size_t count; MyElem data[1]; }; 
  • thread in uscita:

     // allocate the result size_t count = ...; VarLengthArray *retval = malloc( sizeof(VarLengthArray) + sizeof(MyElem) * (count > 0 ? count - 1 : 0) ); // fill the result retval->count = count; for (size_t i = 0; i < retval->count; ++i) { retval->data[i] = ...; } pthread_exit(retval); 
  • raccolta del filo:

     // collect the result void *retval_; if (pthread_join(thread_one_id, &retval_) != 0) { // handle error } VarLengthArray *retval = retval_; // use the result for (size_t i = 0; i < retval->count; ++i) { printf("retval->[%u] = %s\n", (unsigned) i, retval->data[i].string_value); } // deallocate the result free(retval); 

Un esempio completo che utilizza una variabile di condizione e più creator:

 #include  #include  #include  #include  #include  typedef struct Datum { struct Datum *next; char some_data[32]; } Datum; typedef struct SharedData { pthread_mutex_t mutex; pthread_cond_t cond_empty; unsigned seed; Datum *head, *tail; unsigned children_alive; } SharedData; static void *thread_logic(void *argv_); int main(int argc, char **argv) { unsigned thread_count = 2; if (argc > 1) { if (sscanf(argv[1], " %u ", &thread_count) != 1) { fprintf(stderr, "Usage: %s [thread_count]\n", argv[0]); return 1; } } // initialize shared data SharedData shared_data; pthread_mutex_init(&shared_data.mutex, NULL); pthread_cond_init(&shared_data.cond_empty, NULL); shared_data.seed = time(NULL); shared_data.head = NULL; shared_data.tail = NULL; shared_data.children_alive = 0; // start threads detached, so you don't have to call pthread_join pthread_t *child_ids = malloc(sizeof(pthread_t) * thread_count); pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); // start the threads pthread_mutex_lock(&shared_data.mutex); for (unsigned i = 0; i < thread_count; ++i) { if (pthread_create(&child_ids[i], &attr, thread_logic, &shared_data) != 0) { perror("pthread_create"); } else { ++shared_data.children_alive; } } pthread_mutex_unlock(&shared_data.mutex); pthread_attr_destroy(&attr); // loop until all threads are dead while (shared_data.children_alive > 0) { // a condition variable: wait until there is data you can read pthread_mutex_lock(&shared_data.mutex); while (shared_data.head == NULL) { pthread_cond_wait(&shared_data.cond_empty, &shared_data.mutex); } // collect a first datum Datum *datum = shared_data.head; if (datum->next != NULL) { shared_data.head = datum->next; } else { shared_data.head = shared_data.tail = NULL; } pthread_mutex_unlock(&shared_data.mutex); // handle the data (outside of the mutex lock) printf("Got data: %s\n", datum->some_data); free(datum); } return 0; } static void *thread_logic(void *shared_data_) { SharedData *shared_data = shared_data_; while (1) { pthread_mutex_lock(&shared_data->mutex); // create some data useconds_t timeout = ( (((float) (unsigned) rand_r(&shared_data->seed)) / UINT_MAX) * 1000000 ); Datum *datum = malloc(sizeof(Datum)); datum->next = NULL; if (timeout < 1000000 / 25) { --shared_data->children_alive; snprintf(datum->some_data, sizeof(datum->some_data), "I'm done\n"); } else { snprintf( datum->some_data, sizeof(datum->some_data), "Sleeping for %uus\n", timeout ); } // append the datum if (shared_data->head) { shared_data->tail->next = datum; } else { shared_data->head = datum; pthread_cond_signal(&shared_data->cond_empty); } shared_data->tail = datum; pthread_mutex_unlock(&shared_data->mutex); // most likely it takes some time to create the data // do lengthly tasks outside of the mutex lock if (timeout < 1000000 / 25) { return NULL; } else { usleep(timeout); } } }