Resulta que tengo un código que permite intercambiar los valores de un array que se comparte entre varios threads. Cada thread ejecuta un bucle donde escoge dos posiciones de forma aleatoria e intercambia los valores que hay en ellas.
Me piden que modifique el código propuesto para que el código sea más eficiente y el enunciado es este:
En el ejercicio anterior añadimos un mutex para controlar los accesos concurrentes al array. El programa funciona correctamente, pero al haber un solo mutex cada vez que un thread quiere hacer un intercambio tiene que bloquear el acceso a todo el array, aunque podamos tener threads que vayan a intercambiar posiciones distintas. Para ganar en eficiencia vamos a proteger cada posición con un mutex. Para hacer el intercambio de dos variables tendremos, por tanto, que bloquear los dos mutex correspondientes a esas variables. Tenga en cuenta que en este apartado es necesario bloquear dos mutex para hacer cada intercambio, y que esto puede provocar interbloqueos. Aplique alguna de las técnicas de interbloque para evitarlo. Compruebe con el comando time que el programa ejecuta los intercambios en un tiempo menor que con un solo mutex.
El código es el siguiente:
#include <errno.h> #include <pthread.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include "options.h" pthread_mutex_t swap_mutex; //Ejercicio 1 struct buffer { int *data; int size; }; struct thread_info { pthread_t thread_id; // id returned by pthread_create() int thread_num; // application defined thread # }; struct args { int thread_num; // application defined thread # int delay; // delay between operations int iterations; struct buffer *buffer; // Shared buffer }; void *swap(void *ptr) { struct args *args = ptr; int tmpsum; while(args->iterations--) { int i,j, tmp; i=rand() % args->buffer->size; j=rand() % args->buffer->size; printf("Thread %d swapping positions %d(%d) and %d(%d)\n", args->thread_num, i, args->buffer->data[i], j, args->buffer->data[j]); //pthread_mutex_lock(&swap_mutex); //Ejercicio 1 tmp = args->buffer->data[i]; printf("Thread %d tmp positions %d \n", args->thread_num, tmp); if(args->delay) usleep(args->delay); // Force a context switch args->buffer->data[i] = args->buffer->data[j]; printf("Thread %d i<-j positions %d(%d) and %d(%d)\n", args->thread_num, i, args->buffer->data[i], j, args->buffer->data[j]); if(args->delay) usleep(args->delay); args->buffer->data[j] = tmp; printf("Thread %d j<-tmp positions %d(%d) and %d\n", args->thread_num, j, args->buffer->data[j], tmp); if(args->delay) usleep(args->delay); printf("Thread %d buffer ", args->thread_num); tmpsum = 0; for (i = 0; i < args->buffer->size; i++){ tmpsum = args->buffer->data[i] + tmpsum; printf("%i ", args->buffer->data[i]); } printf("\n%i\n",tmpsum); if(args->delay) usleep(args->delay); //pthread_mutex_unlock(&swap_mutex); //Ejercicio 1 } return NULL; } void print_buffer(struct buffer buffer) { int i; for (i = 0; i < buffer.size; i++) printf("%i ", buffer.data[i]); printf("\n"); } void start_threads(struct options opt) { int i; struct thread_info *threads; struct args *args; struct buffer buffer; srand(time(NULL)); if((buffer.data=malloc(opt.buffer_size*sizeof(int)))==NULL) { printf("Out of memory\n"); exit(1); } buffer.size = opt.buffer_size; for(i=0; i<buffer.size; i++) buffer.data[i]=i; printf("creating %d threads\n", opt.num_threads); threads = malloc(sizeof(struct thread_info) * opt.num_threads); args = malloc(sizeof(struct args) * opt.num_threads); if (threads == NULL || args==NULL) { printf("Not enough memory\n"); exit(1); } printf("Buffer before: "); print_buffer(buffer); // Create num_thread threads running swap() for (i = 0; i < opt.num_threads; i++) { threads[i].thread_num = i; args[i].thread_num = i; args[i].buffer = &buffer; args[i].delay = opt.delay; args[i].iterations = opt.iterations; if ( 0 != pthread_create(&threads[i].thread_id, NULL, swap, &args[i])) { printf("Could not create thread #%d", i); exit(1); } } // Wait for the threads to finish for (i = 0; i < opt.num_threads; i++) pthread_join(threads[i].thread_id, NULL); // Print the buffer printf("Buffer after: "); print_buffer(buffer); free(args); free(threads); free(buffer.data); pthread_exit(NULL); } int main (int argc, char **argv) { struct options opt; // Default values for the options opt.num_threads = 10; opt.buffer_size = 10; opt.iterations = 100; opt.delay = 10; read_options(argc, argv, &opt); start_threads(opt); exit (0); }
La que hay que modificar es la función swap. Podéis ver entre comentarios el mutex_lock y unlock que era lo que pedía el primer ejercicio. Pero en este segundo debo hacer como dice en el enunciado. Yo he intentado resolverlo por mi cuenta pero de momento no he sido posible, ya que no encuentro la forma de hacer que no se repitan valores en los intercambios y además bajar el tiempo de ejecución del código, que es lo que hay que hacer. Os agradecería mucho si me pudierais ayudar a dar con la solución.
Muchas gracias