Clasificación de combinación simultánea en memoria compartida

Dado un número ‘n’ y un número, ordene los números usando la clasificación de combinación simultánea . (Sugerencia: intente usar llamadas al sistema shmget, shmat).
Parte 1: El algoritmo (¿CÓMO?) 
Crea recursivamente dos procesos secundarios, uno para la mitad izquierda y otro para la mitad derecha. Si el número de elementos en la array para un proceso es inferior a 5, realice una ordenación por inserción . El padre de los dos hijos fusiona el resultado y regresa al padre y así sucesivamente. Pero, ¿cómo lo haces concurrente?
Parte 2: La lógica (¿POR QUÉ?) 
La parte importante de la solución a este problema no es algorítmica, sino explicar conceptos de Sistema Operativo y kernel. 
Para lograr la clasificación simultánea, necesitamos una forma de hacer que dos procesos funcionen en la misma array al mismo tiempo. Para facilitar las cosas, Linux proporciona muchas llamadas al sistema a través de puntos finales de API simples. Dos de ellos son, shmget() (para asignación de memoria compartida) y shmat() (para operaciones de memoria compartida). Creamos un espacio de memoria compartida entre el proceso hijo que bifurcamos. Cada segmento se divide en hijo izquierdo y derecho que se ordena, ¡la parte interesante es que están trabajando simultáneamente! El shmget() solicita al núcleo que asigne una página compartida para ambos procesos. ¿Por qué la bifurcación tradicional() no funciona?
 
La respuesta está en lo que realmente hace fork(). De la documentación, «fork() crea un nuevo proceso al duplicar el proceso de llamada». El proceso hijo y el proceso padre se ejecutan en espacios de memoria separados. En el momento de fork() ambos espacios de memoria tienen el mismo contenido. Las escrituras en memoria, los cambios en el descriptor de archivo (fd), etc., realizados por uno de los procesos no afectan al otro. Por lo tanto, necesitamos un segmento de memoria compartida.
 

CPP

// C program to implement concurrent merge sort
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
 
void insertionSort(int arr[], int n);
void merge(int a[], int l1, int h1, int h2);
 
void mergeSort(int a[], int l, int h)
{
    int i, len=(h-l+1);
 
    // Using insertion sort for small sized array
    if (len<=5)
    {
        insertionSort(a+l, len);
        return;
    }
 
    pid_t lpid,rpid;
    lpid = fork();
    if (lpid<0)
    {
        // Lchild proc not created
        perror("Left Child Proc. not created\n");
        _exit(-1);
    }
    else if (lpid==0)
    {
        mergeSort(a,l,l+len/2-1);
        _exit(0);
    }
    else
    {
        rpid = fork();
        if (rpid<0)
        {
            // Rchild proc not created
            perror("Right Child Proc. not created\n");
            _exit(-1);
        }
        else if(rpid==0)
        {
            mergeSort(a,l+len/2,h);
            _exit(0);
        }
    }
 
    int status;
 
    // Wait for child processes to finish
    waitpid(lpid, &status, 0);
    waitpid(rpid, &status, 0);
 
    // Merge the sorted subarrays
    merge(a, l, l+len/2-1, h);
}
 
/* Function to sort an array using insertion sort*/
void insertionSort(int arr[], int n)
{
   int i, key, j;
   for (i = 1; i < n; i++)
   {
       key = arr[i];
       j = i-1;
 
       /* Move elements of arr[0..i-1], that are
          greater than key, to one position ahead
          of their current position */
       while (j >= 0 && arr[j] > key)
       {
           arr[j+1] = arr[j];
           j = j-1;
       }
       arr[j+1] = key;
   }
}
 
// Method to merge sorted subarrays
void merge(int a[], int l1, int h1, int h2)
{
    // We can directly copy  the sorted elements
    // in the final array, no need for a temporary
    // sorted array.
    int count=h2-l1+1;
    int sorted[count];
    int i=l1, k=h1+1, m=0;
    while (i<=h1 && k<=h2)
    {
        if (a[i]<a[k])
            sorted[m++]=a[i++];
        else if (a[k]<a[i])
            sorted[m++]=a[k++];
        else if (a[i]==a[k])
        {
            sorted[m++]=a[i++];
            sorted[m++]=a[k++];
        }
    }
 
    while (i<=h1)
        sorted[m++]=a[i++];
 
    while (k<=h2)
        sorted[m++]=a[k++];
 
    int arr_count = l1;
    for (i=0; i<count; i++,l1++)
        a[l1] = sorted[i];
}
 
// To check if array is actually sorted or not
void isSorted(int arr[], int len)
{
    if (len==1)
    {
        printf("Sorting Done Successfully\n");
        return;
    }
 
    int i;
    for (i=1; i<len; i++)
    {
        if (arr[i]<arr[i-1])
        {
            printf("Sorting Not Done\n");
            return;
        }
    }
    printf("Sorting Done Successfully\n");
    return;
}
 
// To fill random values in array for testing
// purpose
void fillData(int a[], int len)
{
    // Create random arrays
    int i;
    for (i=0; i<len; i++)
        a[i] = rand();
    return;
}
 
// Driver code
int main()
{
    int shmid;
    key_t key = IPC_PRIVATE;
    int *shm_array;
 
 
    // Using fixed size array.  We can uncomment
    // below lines to take size from user
    int length = 128;
 
    /* printf("Enter No of elements of Array:");
    scanf("%d",&length); */
 
    // Calculate segment length
    size_t SHM_SIZE = sizeof(int)*length;
 
    // Create the segment.
    if ((shmid = shmget(key, SHM_SIZE, IPC_CREAT | 0666)) < 0)
    {
        perror("shmget");
        _exit(1);
    }
 
    // Now we attach the segment to our data space.
    if ((shm_array = shmat(shmid, NULL, 0)) == (int *) -1)
    {
        perror("shmat");
        _exit(1);
    }
 
    // Create a random array of given length
    srand(time(NULL));
    fillData(shm_array, length);
 
    // Sort the created array
    mergeSort(shm_array, 0, length-1);
 
    // Check if array is sorted or not
    isSorted(shm_array, length);
 
    /* Detach from the shared memory now that we are
       done using it. */
    if (shmdt(shm_array) == -1)
    {
        perror("shmdt");
        _exit(1);
    }
 
    /* Delete the shared memory segment. */
    if (shmctl(shmid, IPC_RMID, NULL) == -1)
    {
        perror("shmctl");
        _exit(1);
    }
 
    return 0;
}

Producción: 
 

Sorting Done Successfully

¿Mejoras de rendimiento?  
Intente cronometrar el código y compare su rendimiento con el código secuencial tradicional. ¡Te sorprendería saber que el rendimiento de clasificación secuencial es mejor! 
Cuando, digamos hijo izquierdo, accede a la array izquierda, la array se carga en la memoria caché de un procesador. Ahora, cuando se accede a la array derecha (debido a los accesos simultáneos), se pierde la memoria caché, ya que la memoria caché se llena con el segmento izquierdo y luego el segmento derecho se copia en la memoria caché. Este proceso de ida y vuelta continúa y degrada el rendimiento a tal nivel que funciona peor que el código secuencial.
Hay formas de reducir los errores de caché controlando el flujo de trabajo del código. ¡Pero no se pueden evitar por completo!
Este artículo es una contribución de Pinkesh Badjatiya.Si le gusta GeeksforGeeks y le gustaría contribuir, también puede escribir un artículo usando write.geeksforgeeks.org o enviar su artículo por correo a review-team@geeksforgeeks.org. Vea su artículo que aparece en la página principal de GeeksforGeeks y ayude a otros Geeks.
Escriba comentarios si encuentra algo incorrecto o si desea compartir más información sobre el tema tratado anteriormente.
 

Publicación traducida automáticamente

Artículo escrito por GeeksforGeeks-1 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *