Le programme IO de fichiers multithreads se comporte de manière imprévisible lorsque le nombre de threads est augmenté

Essayez de créer un fichier de 1Mo (1048576Byte) en écrivant dans différentes tailles de morceaux et un nombre différent de threads. Lorsque int NUM_THREADS = 2 ou int NUM_THREADS = 1 , la taille du fichier créé est identique à celle indiquée, c’est-à-dire 10 Mo.

Cependant, lorsque j’augmente le nombre de threads à 4, la taille du fichier créé est d’environ 400 Mo; Pourquoi cette anomalie?

 #include  #include  #include  #define TenGBtoByte 1048576 #define fileToWrite "/tmp/schatterjee.txt" using namespace std; pthread_mutex_t mutexsum; struct workDetails { int threadcount; int chunkSize; char *data; }; void *SPWork(void *threadarg) { struct workDetails *thisWork; thisWork = (struct workDetails *) threadarg; int threadcount = thisWork->threadcount; int chunkSize = thisWork->chunkSize; char *data = thisWork->data; long noOfWrites = (TenGBtoByte / (threadcount * chunkSize)); FILE *f = fopen(fileToWrite, "a+"); for (long i = 0; i < noOfWrites; ++i) { pthread_mutex_lock(&mutexsum); fprintf(f, "%s", data); fflush (f); pthread_mutex_unlock(&mutexsum); } fclose(f); pthread_exit((void *) NULL); } int main(int argc, char *argv[]) { int blocksize[] = {1024}; int NUM_THREADS = 2; for (int BLOCKSIZE: blocksize) { char *data = new char[BLOCKSIZE]; fill_n(data, BLOCKSIZE, 'x'); pthread_t thread[NUM_THREADS]; workDetails detail[NUM_THREADS]; pthread_attr_t attr; int rc; long threadNo; void *status; /* Initialize and set thread detached attribute */ pthread_mutex_init(&mutexsum, NULL); pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); for (threadNo = 0; threadNo < NUM_THREADS; threadNo++) { detail[threadNo].threadcount = NUM_THREADS; detail[threadNo].chunkSize = BLOCKSIZE; detail[threadNo].data = data; rc = pthread_create(&thread[threadNo], &attr, SPWork, (void *) &detail[threadNo]); if (rc) exit(-1); } pthread_attr_destroy(&attr); for (threadNo = 0; threadNo < NUM_THREADS; threadNo++) { rc = pthread_join(thread[threadNo], &status); if (rc) exit(-1); } pthread_mutex_destroy(&mutexsum); delete[] data; } pthread_exit(NULL); } 

NB – 1) C’est une tâche de benchmarking, donc faites comme ils l’avaient demandé. 2) long noOfWrites = (TenGBtoByte / (threadcount * chunkSize)); Calculez essentiellement le nombre de fois que chaque thread doit écrire pour obtenir la taille combinée de 10 Mo. 4) J’ai essayé de mettre le verrou Mutex à différentes positions. Tous yeild dans le même résultat

Des suggestions concernant d’autres modifications du programme sont également les bienvenues.

Vous allouez et initialisez votre tableau de données comme ceci:

 char *data = new char[BLOCKSIZE]; fill_n(data, BLOCKSIZE, 'x'); 

Ensuite, vous l’écrivez dans un fichier en utilisant fprintf :

 fprintf(f, "%s", data); 

La fonction fprintf s’attend à ce que les data soient une chaîne terminée par un zéro. C’est déjà un comportement indéfini. Si cela fonctionne avec un faible nombre de threads, c’est parce que la mémoire après morceau de mémoire contient zéro octet.

En dehors de cela, mutex dans votre programme ne sert à rien et peut être supprimé. Le locking de fichier est également redondant. Vous pouvez donc utiliser fwrite_unlocked et fflush_unlocked pour écrire vos données, car chaque thread utilise un object FILE distinct. Essentiellement, toute la synchronisation dans votre programme est effectuée dans le kernel, pas dans l’espace utilisateur.

Même après avoir supprimé mutex et utilisé les fonctions _unlocked , votre programme crée de manière fiable des fichiers de 1 Mo, quel que soit le nombre de threads. L’écriture de fichier non valide semble être le seul problème que vous rencontrez.

@ Ivan Oui! Oui! Oui! Vous avez absolument raison mon ami. Sauf pour un petit fait. Le mutex est nécessaire. Ceci est le code final. Essayez de supprimer le mutex et la taille du fichier sera différente.

 #include  #include  #include  #define TenGBtoByte 1048576 #define fileToWrite "/tmp/schatterjee.txt" using namespace std; pthread_mutex_t mutexsum;; struct workDetails { int threadcount; int chunkSize; char *data; }; void *SPWork(void *threadarg) { struct workDetails *thisWork; thisWork = (struct workDetails *) threadarg; int threadcount = thisWork->threadcount; int chunkSize = thisWork->chunkSize; char *data = thisWork->data; long noOfWrites = (TenGBtoByte / (threadcount * chunkSize)); FILE *f = fopen(fileToWrite, "a+"); for (long i = 0; i < noOfWrites; ++i) { pthread_mutex_lock(&mutexsum); fprintf(f, "%s", data); fflush (f); pthread_mutex_unlock(&mutexsum); } fclose(f); pthread_exit((void *) NULL); } int main(int argc, char *argv[]) { int blocksize[] = {1024}; int NUM_THREADS = 128; for (int BLOCKSIZE: blocksize) { char *data = new char[BLOCKSIZE+1]; fill_n(data, BLOCKSIZE, 'x'); data[BLOCKSIZE] = NULL; pthread_t thread[NUM_THREADS]; workDetails detail[NUM_THREADS]; pthread_attr_t attr; int rc; long threadNo; void *status; pthread_mutex_init(&mutexsum, NULL); pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); for (threadNo = 0; threadNo < NUM_THREADS; threadNo++) { detail[threadNo].threadcount = NUM_THREADS; detail[threadNo].chunkSize = BLOCKSIZE; detail[threadNo].data = data; rc = pthread_create(&thread[threadNo], &attr, SPWork, (void *) &detail[threadNo]); if (rc) exit(-1); } pthread_attr_destroy(&attr); for (threadNo = 0; threadNo < NUM_THREADS; threadNo++) { rc = pthread_join(thread[threadNo], &status); if (rc) exit(-1); } pthread_mutex_destroy(&mutexsum); delete[] data; } pthread_exit(NULL); }