Advertisement
Guest User

Untitled

a guest
Dec 14th, 2019
168
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 13.47 KB | None | 0 0
  1. #define BLANCO -10
  2. #define GRIS -20
  3. #define NEGRO -30
  4.  
  5. /* MAXIMO VALOR DE INT */
  6. int IMAX = numeric_limits<int>::max();
  7.  
  8.  
  9.  
  10. struct threadParams{
  11.     int id;
  12.     int nodoActual;
  13.     Grafo arbol_local;
  14.     //Podria usarse un heap!
  15.     vector<int> distancia; //(g->cantNodos, IMAX);
  16.     vector<int> distanciaNodo;
  17.     vector<int> colores;
  18.     atomic<bool> encolado;
  19.     mutex puedo_pintar;
  20.     mutex listo_para_encolar;
  21.     threadParams(int index, int cantNodos){
  22.         nodoActual = -1;
  23.         arbol_local = Grafo();
  24.         id = index;
  25.         distancia.assign(cantNodos,IMAX);
  26.         distanciaNodo.assign(cantNodos,-1);
  27.         colores = vector<int>(cantNodos, BLANCO);
  28.         bool unBool = false;
  29.         encolado.store(unBool);
  30.     }
  31. };
  32.  
  33. struct infoMerge{
  34.     threadParams * emisor;
  35.     int nodo_emisor;
  36.     int nodo_receptor;
  37.     int peso;
  38.     infoMerge(threadParams* emi, int n_emisor, int n_receptor, int p){
  39.         emisor = emi;
  40.         nodo_emisor = n_emisor;
  41.         nodo_receptor = n_receptor;
  42.         peso = p;
  43.     }
  44. };
  45.  
  46.  
  47. void restart_thread(threadParams*);
  48.  
  49. //COLORES de los nodos
  50. vector<int> g_colores;
  51.  
  52. vector<queue<infoMerge>> g_colas_fusion;
  53. vector<threadParams*> params;
  54.  
  55. //Grafo (variable global)
  56. Grafo g_grafo;
  57.  
  58. //MUTEX DEL SISTEMA
  59. vector<mutex> g_fusion_mutex;
  60. vector<mutex> g_colores_mutex;
  61. vector<mutex> g_colas_mutex;
  62. //VECTOR DE ATENDIDOS
  63. vector<bool> atendidos;
  64. int itTotales = 0;
  65. int itThread1 = 0;
  66.  
  67. //DISTANCIA mínima del nodo al árbol
  68. vector<int> g_distancia;
  69. vector<int> g_distanciaNodo;
  70.  
  71. //Mutex de debug
  72. mutex debugMutex;
  73.  
  74. //Variable atomica
  75. bool algunoTermino;
  76.  
  77.  
  78. //Pinto el nodo de negro para marcar que fue puesto en el árbol
  79. void pintarNodo(int num){
  80.   g_colores[num] = NEGRO;
  81.   //Para no volver a elegirlo
  82.   g_distancia[num] = IMAX;
  83. }
  84.  
  85. //Pinto los vecinos de gris para marcar que son alcanzables desde el árbol (salvo los que ya son del árbol)
  86. void pintarVecinos(Grafo *g, int num){
  87.   for(vector<Eje>::iterator v = g->vecinosBegin(num); v != g->vecinosEnd(num); ++v){
  88.     //Es la primera vez que descubro el nodo
  89.     if(g_colores[v->nodoDestino] == BLANCO){
  90.         //Lo marco como accesible
  91.         g_colores[v->nodoDestino] = GRIS;
  92.         //Le pongo el peso desde donde lo puedo acceder
  93.         g_distancia[v->nodoDestino] = v->peso;
  94.         //Guardo que nodo me garantiza esa distancia
  95.         g_distanciaNodo[v->nodoDestino] = num;
  96.     }else if(g_colores[v->nodoDestino] == GRIS){
  97.         //Si ya era accesible, veo si encontré un camino más corto
  98.         g_distancia[v->nodoDestino] = min(v->peso,g_distancia[v->nodoDestino]);
  99.         //Guardo que nodo me garantiza esa distancia
  100.         if(g_distancia[v->nodoDestino] == v->peso)
  101.         g_distanciaNodo[v->nodoDestino] = num;
  102.     }
  103.   }
  104. }
  105.  
  106. void pintarVecinos(int nodo, threadParams* param){
  107.  
  108.     for(vector<Eje>::iterator v = g_grafo.vecinosBegin(nodo); v != g_grafo.vecinosEnd(nodo); ++v){
  109.     //Es la primera vez que descubro el nodo
  110.     if(param->colores[v->nodoDestino] == BLANCO){
  111.         //Lo marco como accesible
  112.         param->colores[v->nodoDestino] = GRIS;
  113.         //Le pongo el peso desde donde lo puedo acceder
  114.         param->distancia[v->nodoDestino] = v->peso;
  115.         //Guardo que nodo me garantiza esa distancia
  116.         param->distanciaNodo[v->nodoDestino] = nodo;
  117.     }else if(param->colores[v->nodoDestino] == GRIS){
  118.         //Si ya era accesible, veo si encontré un camino más corto
  119.         param->distancia[v->nodoDestino] = min(v->peso,param->distancia[v->nodoDestino]);
  120.         //Guardo que nodo me garantiza esa distancia
  121.         if(param->distancia[v->nodoDestino] == v->peso){
  122.             param->distanciaNodo[v->nodoDestino] = nodo;
  123.         }
  124.  
  125.     }
  126.   }
  127.  
  128. }
  129.  
  130. //El emisor le pasa su data al receptor
  131. void fusionarArboles(infoMerge& emisor_info, threadParams* receptor){
  132.  
  133.     threadParams * emisor = emisor_info.emisor;
  134.   emisor->listo_para_encolar.lock();
  135.    
  136.     printf("[%d] tiene %d nodos, %d ejes y %d peso, el emisor es %d y tiene %d nodos, %d ejes y %d peso\n",
  137.         receptor->id, receptor->arbol_local.numVertices, receptor->arbol_local.numEjes, receptor -> arbol_local.pesoTotal(),
  138.         emisor->id, emisor->arbol_local.numVertices, emisor->arbol_local.numEjes, emisor -> arbol_local.pesoTotal());
  139.    
  140.     for(int i = 0; i < g_colores.size(); i++){
  141.         if(emisor->colores[i] == emisor->id){
  142.             assert(receptor -> colores[i] != receptor->id);
  143.             receptor->colores[i] = receptor->id;
  144.             receptor->distancia[i] = IMAX;
  145.             receptor->distanciaNodo[i] = emisor->distanciaNodo[i];
  146.  
  147.             //cambio el color en el grafo
  148.             g_colores_mutex[i].lock();
  149.             g_colores[i] = receptor->id;
  150.             g_colores_mutex[i].unlock();
  151.         }
  152.         if(emisor->colores[i] == GRIS && receptor->colores[i] != receptor->id){
  153.             receptor->distancia[i] = receptor->distancia[i] < emisor->distancia[i]
  154.                                 ? receptor->distancia[i] : emisor->distancia[i];
  155.             receptor->distanciaNodo[i] = receptor->distancia[i] < emisor->distancia[i]
  156.                                 ? receptor->distanciaNodo[i] : emisor->distanciaNodo[i];
  157.             receptor->colores[i] = GRIS;
  158.  
  159.         }
  160.     }
  161.  
  162.     auto cantEjes = 0;
  163.     for(auto vertice : emisor->arbol_local.listaDeAdyacencias){
  164.         for(auto eje : vertice.second){
  165.             if(receptor->arbol_local.listaDeAdyacencias.count(vertice.first) != 0){
  166.                 receptor->arbol_local.listaDeAdyacencias.at(vertice.first).push_back(eje);
  167.                 cantEjes++;
  168.             }else{
  169.                 receptor->arbol_local.listaDeAdyacencias.insert(make_pair(vertice.first, vector<Eje>()));
  170.                 receptor->arbol_local.listaDeAdyacencias.at(vertice.first).push_back(eje);
  171.                 cantEjes++;
  172.             }
  173.         }
  174.     }
  175.     receptor->arbol_local.numEjes += cantEjes / 2;
  176.  
  177.     if(receptor-> arbol_local.numVertices  > 0 && emisor -> arbol_local.numVertices  > 0){
  178.         //Agregamos el eje sobre el que se hizo la fusion
  179.         int nodo = emisor_info.nodo_receptor;
  180.         int otroNodo = emisor_info.nodo_emisor;
  181.         int pesoArista = emisor_info.peso;
  182.        
  183.         debugMutex.lock();
  184.         printf("[%d] esta uniendo su arbol con el de %d con el eje (%d, %d p:%d)\n",
  185.             receptor -> id, emisor -> id, nodo, otroNodo, pesoArista);
  186.         printf("emisor\n");
  187.         imprimirVector(emisor -> distanciaNodo);
  188.        
  189.         assert(nodo != -1);
  190.         assert(otroNodo != -1);
  191.         debugMutex.unlock();
  192.  
  193.         receptor->arbol_local.insertarEje(nodo, otroNodo, pesoArista);
  194.     }
  195.     receptor->arbol_local.numVertices += emisor->arbol_local.numVertices;
  196.     auto numEjesPost = receptor->arbol_local.numEjes;
  197.  
  198.     g_colas_mutex[emisor->id].lock();
  199.  
  200.     //Fusiono las colas
  201.     while(!g_colas_fusion[emisor->id].empty()){
  202.         auto thread = g_colas_fusion[emisor->id].front();
  203.         g_colas_fusion[emisor->id].pop();
  204.         g_colas_fusion[receptor->id].push(thread);
  205.     }
  206.     g_colas_mutex[emisor->id].unlock();
  207. }
  208.  
  209.  
  210.  
  211. bool chequeoDeCola(threadParams* thread){
  212.     g_colas_mutex[thread->id].lock();
  213.     while(!g_colas_fusion[thread->id].empty() && !algunoTermino){
  214.         infoMerge otroThread = g_colas_fusion[thread->id].front();
  215.         g_colas_fusion[thread->id].pop();
  216.        
  217.         debugMutex.lock();
  218.         printf("[%d] voy comer a %d, nodo actual es %d\n", thread -> id,(otroThread.emisor)->id, thread->nodoActual);
  219.         debugMutex.unlock();
  220.        
  221.         fusionarArboles(otroThread, thread);
  222.        
  223.         debugMutex.lock();
  224.         printf("[%d] comi a %d, nodo actual es %d\n", thread -> id,(otroThread.emisor)->id,thread->nodoActual);
  225.         debugMutex.unlock();
  226.        
  227.         atendidos[(otroThread.emisor)->id] = true;
  228.     (otroThread.emisor)->puedo_pintar.unlock();
  229.     }
  230.     g_colas_mutex[thread->id].unlock();
  231.     return false;
  232. }
  233.  
  234. bool meEstanEncolando(threadParams* param) {
  235.   if (param->encolado.load()) {
  236.     while(!atendidos[param->id]){}
  237.     return true;
  238.   }
  239.   return false;
  240. }
  241.  
  242. //retorno si pude pintar el nodo de mi color o no
  243. bool pintarNodo(int num, threadParams* param){
  244.     g_colores_mutex[num].lock();
  245.     int colorFusion = g_colores[num];
  246.    
  247.     debugMutex.lock();
  248.     printf("[%d] queria pintar %d y era de %d, tiene %d nodos\n", param -> id, num, colorFusion, param -> arbol_local.numVertices);
  249.     debugMutex.unlock();
  250.    
  251.     assert(colorFusion != param->id);
  252.     bool expected = false;
  253.   bool value = true;
  254.     if(colorFusion != BLANCO){
  255.         //Si mi id es mayor al del thread con el que colisione, me encolo y espero
  256.         if(colorFusion < param->id && param->encolado.compare_exchange_strong(expected, value)){
  257.  
  258.             //Lockeo la cola a la cual me voy a pushear
  259.       param->puedo_pintar.unlock();
  260.       if(param -> arbol_local.numVertices >0){
  261.  
  262.             g_colas_mutex[g_colores[num]].lock();
  263.             //Me pusheo a la cola
  264.             infoMerge emisor(param, param->distanciaNodo[num], num,param->distancia[num]);
  265.             g_colas_fusion[g_colores[num]].push(emisor);
  266.             //Unlockeo la cola a la cual me pushie
  267.            
  268.             debugMutex.lock();
  269.             printf("[%d] encontre a %d en el eje (%d, %d p:%d) y me encole\n",
  270.                 param -> id, colorFusion, param->distanciaNodo[num], num,
  271.                 param->distancia[num]);
  272.             if(num == -1 || param -> distanciaNodo[num] == -1){
  273.                 printf("[%d] la distancia de los nodos (%lu) es:\n", param -> id, (param -> distanciaNodo).size());
  274.                 for(uint i = 0; i < param -> distanciaNodo.size(); i++){
  275.                     printf("(%d, %d) ", param -> distanciaNodo[i], i);
  276.                 }
  277.                 printf("\n[%d] los colores (%lu) son:\n", param -> id, (param -> colores).size());
  278.                 for(uint i = 0; i < param -> colores.size(); i++){
  279.                     printf("(%d, %d) ", i, param -> colores[i]);
  280.                 }
  281.             }
  282.             debugMutex.unlock();
  283.            
  284.             g_colas_mutex[g_colores[num]].unlock();
  285.       }
  286.       else{
  287.         atendidos[param->id] = true;
  288.       }
  289.  
  290.             // Espero a que me atiendan
  291.             //Unlockeo el nodo por si otro tambien lo quiere pintar
  292.             g_colores_mutex[num].unlock();
  293.             while(!atendidos[param->id]){}
  294.                 return false;
  295.         } else if (colorFusion < param->id) {
  296.       while(!atendidos[param->id]){}
  297.       return false;
  298.     }
  299.         else{
  300.             //Unlockeo el nodo por si otro tambien lo quiere pintar
  301.       threadParams* threadAComer = params[colorFusion];
  302.         g_colores_mutex[num].unlock();
  303.       threadAComer->puedo_pintar.lock();
  304.       if (threadAComer->encolado.compare_exchange_strong(expected, value)) {
  305.         if(g_colores[num] != colorFusion){
  306.         //NO HACE FALTA LOCKEAR ACA, POR QUE UN THREAD NO PUEDE REINICIAR Y VOLVER A TENER EL MISMO NODO, COMO MUCHO LO TIENE ALGUIEN DE MENOR NIVEL Y NO ME IMPORTA QUIEN
  307.             bool reverted = false;
  308.             threadAComer->encolado = reverted;
  309.  
  310.             threadAComer->puedo_pintar.unlock();
  311.            
  312.             debugMutex.lock();
  313.                     printf("[%d] encontre a %d en el eje (%d, %d p:%d) pero ya habia reseteado\n", param -> id,threadAComer->id , num, param->distanciaNodo[num], param->distancia[num]);
  314.                     debugMutex.unlock();
  315.                    
  316.         }
  317.         else{
  318.                 //Pusheo al que voy a comer a la cola
  319.  
  320.             g_colas_mutex[param->id].lock();
  321.                     infoMerge emisor(threadAComer, num, param->distanciaNodo[num],param->distancia[num]);
  322.                     g_colas_fusion[param->id].push(emisor);
  323.                    
  324.                    
  325.                     debugMutex.lock();
  326.                     printf("[%d] encontre a %d en el eje (%d, %d p:%d) y lo encole\n", param -> id,threadAComer->id , num, param->distanciaNodo[num], param->distancia[num]);
  327.                     debugMutex.unlock();
  328.                    
  329.                     g_colas_mutex[param->id].unlock();
  330.         }
  331.             //Unlockeo la cola a la cual me pushie
  332.       } else {
  333.             threadAComer->puedo_pintar.unlock();
  334.       }
  335.       param->listo_para_encolar.lock();
  336.             chequeoDeCola(param);
  337.             return true;
  338.         }
  339.     } else if(!meEstanEncolando(param)){
  340.       //Como voy a pintar, tengo que esperar a marcar mis vecinos antes de dejar que me coman
  341.       param->listo_para_encolar.lock();
  342.             param->arbol_local.numVertices += 1;
  343.             g_colores[num] = param->id;
  344.             param->colores[num] = param->id;
  345.             if(param->arbol_local.numVertices > 1){
  346.                 param->arbol_local.insertarEje(num,param->distanciaNodo[num],param->distancia[num]);
  347.             }
  348.             else{
  349.                 param -> distanciaNodo[num] = -2;//es la raiz
  350.             }
  351.             param->distancia[num] = IMAX;
  352.       g_colores_mutex[num].unlock();
  353.       return true;
  354.         }
  355.   g_colores_mutex[num].unlock();
  356.     return false;
  357. }
  358.  
  359. void* mstThread(void* p_param){
  360.     auto pesoEjes = 0;
  361.     threadParams* param = ((threadParams*)p_param);
  362.     param->nodoActual = rand() % g_grafo.numVertices;
  363.      while(param->arbol_local.numVertices != g_grafo.numVertices){
  364.         auto numEjes = param->arbol_local.numEjes;
  365.         if(algunoTermino) goto end;
  366.         int numeroVertices = param->arbol_local.numVertices;
  367.         //Lo pinto de NEGRO para marcar que lo agregué al árbol y borro la distancia
  368.         param->puedo_pintar.lock();
  369.         if(meEstanEncolando(param) || !pintarNodo(param->nodoActual,param)){
  370.             goto restart;
  371.         }
  372.         param->puedo_pintar.unlock();
  373.         //QUIERO ACTUALIZAR MIS VECINOS SOLO SI PINTE ALGO O ME FUSIONE, SI NO, NO!
  374.         if(numeroVertices < param->arbol_local.numVertices) {
  375.             //Descubrir vecinos: los pinto y calculo distancias
  376.            
  377.             if(param->colores[param->nodoActual] != param->id){
  378.                 debugMutex.lock();
  379.                 printf("[%d] busco pintar vecinos y actualizar nodo actual %d que no es mio, es de %d\n", param->id, param->nodoActual,param->colores[param->nodoActual]);
  380.                 debugMutex.unlock();
  381.             }
  382.            
  383.             if(param->colores[param->nodoActual] == param->id){
  384.                 pintarVecinos(param->nodoActual, param);
  385.         //Una vez que termino de marcar mis vecinos estoy liste para que me coman
  386.             //Busco el nodo más cercano que no esté en el árbol, pero sea alcanzable
  387.             param->nodoActual = min_element(param->distancia.begin(),param->distancia.end()) - param->distancia.begin();
  388.             }
  389.         }
  390.         param->listo_para_encolar.unlock();
  391.       }
  392.  
  393.     algunoTermino = true;
  394.     //param.arbol_local.imprimirGrafo();
  395.     assert(param->arbol_local.numEjes == (g_grafo.numVertices - 1));
  396.     assert(g_grafo.numVertices == param->arbol_local.numVertices);
  397.     printf("termino peso: %d\n",param->arbol_local.pesoTotal());
  398.     for(int i = 0; i < atendidos.size(); i++){
  399.         atendidos[i] = true;
  400.     }
  401.  
  402.   end:
  403.   return nullptr;
  404.   restart:
  405.     restart_thread( param);
  406. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement