Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: patilanz en 15 Mayo 2014, 13:33 pm



Título: Duda con threads
Publicado por: patilanz en 15 Mayo 2014, 13:33 pm
Hola me acabo de enterar de que existe thread http://www.cplusplus.com/reference/thread/thread/

Esto me gusto porque deberia de funcionar en todos los os.
Luego probe hacer esto:

Código
  1. #include <thread>
  2. #include <stdio.h>
  3. #include <thread>
  4. #include <iostream>
  5.  
  6. using namespace std;
  7. void hilo(int n){
  8. int i=0;
  9. while(i<100){
  10. i++;
  11. cout << "Thread " << n << " :" << i << endl;
  12. }
  13. }
  14.  
  15. int main(int argc, char ** argv){
  16. thread test(hilo,1);
  17. test.join();
  18. thread test2(hilo,2);
  19. test2.join();
  20. getchar();
  21. }

Y el resultado fue como si hubiera puesto dos whiles seguidos. No deberia de mostrar se por ejemplo:

Thread 1: 1
Thread 2: 1
Thread 1: 2
...
En vez de:

Thread 1: 1
Thread 1: 2
...
Thread 1: 100
Thread 2: 1
..


O tengo confundido lo que hacen los threads?

Saludos


Título: Re: Duda con threads
Publicado por: NikNitro! en 15 Mayo 2014, 13:47 pm
los threads se ejecutan de forma aleatoria. No tienen por qué ocurrir siempre igual.

De todos modos no estoy seguro de que en c++ se usen así.

En Java (que es donde los estoy dando actualmente) tienes que hacer que la clase extienda de threadable y llamar a un método que es run() el cual es override.

Saludos


Título: Re: Duda con threads
Publicado por: patilanz en 15 Mayo 2014, 13:49 pm
En mi caso no se ejecutan de forma aleatoria porque va todo seguido como en dos whiles seguidos.


Título: Re: Duda con threads
Publicado por: amchacon en 15 Mayo 2014, 13:52 pm
No hay ningún problema ahí, nadie te garantiza que un thread van a ir al mismo tiempo (depende de los núcleos físicos que tengas, la carga del sistema...).

Si quieres un orden fijo, tendrás que sincronizar los threads con los mecanismos correspondientes.



Vale lo acabo de revisar y efectivamente has metido la gamba xD.

El problema está aquí:
Código
  1. thread test(hilo,1);
  2. test.join();
  3. thread test2(hilo,2);
  4. test2.join();

Ponlo así:
Código
  1. thread test(hilo,1);
  2. thread test2(hilo,2);
  3. test.join();
  4. test2.join();

El join no es para iniciar el thread, sino para esperar a que acabe xD


Título: Re: Duda con threads
Publicado por: patilanz en 15 Mayo 2014, 17:56 pm
Gracias ahora funciona perfecto  ;D
Pero si es para esperar a que acabe que hace? Cuando acaba la función limpia memoria o algo así?
Puedo detectar que el thread se ha cerrado y ejecutar otra función con join?


Título: Re: Duda con threads
Publicado por: amchacon en 15 Mayo 2014, 21:39 pm
La idea es la perfecta sincronización, si vas a salir del programa tendrás que esperar a que terminen el resto de los hilos. De lo contrario podría tener efectos adversos.

La clase thread presupone que harás join en algún momento (al final del programa/funcion normalmente), si tu idea es dejar el hilo a tu aire tienes que usar detach():
Código
  1. thread t(hilo);
  2. t.detach();

Pero pocos son los casos que es necesario tirar por ahí.

Citar
Puedo detectar que el thread se ha cerrado
¿Sin usar join?

No, a no ser que te pongas un booleano de control en el hilo... Lo más natural sería el uso de condiction_variables.

Citar
y ejecutar otra función con join?
No, una vez que haz hecho join no puedes ejecutar otra funcion.

Aunque si puedes aprovecharte del move-constructor y crear otro objeto thread:
Código
  1. thread t(hilo);
  2. t.join();
  3.  
  4. t = thread(hilo2); // move contructor


Título: Re: Duda con threads
Publicado por: patilanz en 17 Mayo 2014, 13:17 pm
Hola gracias por tu explicacion pero ahora tambien con los threads pero anadiendo socket de windows este codigo funciona fuera de un thread pero si lo pongo dentro de una funcion que llamo desde el thread pasando le los parametros me da error abort was called.

Código
  1. void newClient(SOCKET &socket_s,SOCKET &socket_c,sockaddr_in &client){
  2. cout << "Socket from: " << inet_ntoa(client.sin_addr) << endl;
  3. char buffer[512];
  4. int result=recv(socket_c,buffer,sizeof(buffer),0);
  5. if(result==-1)
  6. return (void)WSAGetLastError();
  7. cout << buffer;
  8. }
  9. thread(newClient,socket_s,socket_c,client);
  10.  

Si pongo el codigo directamente en la funcion main donde se hace el acept funciona pero en cambio en la funcion con el thread no.

Si llamo la funcion aparte si funciona... ??
Porque??

Saludos y gracias


Título: Re: Duda con threads
Publicado por: ivancea96 en 17 Mayo 2014, 13:29 pm
Asegúrate de hacerle .join() o .detach() al thread.


Título: Re: Duda con threads
Publicado por: amchacon en 17 Mayo 2014, 16:49 pm
Hay varios errores ahí.

El primero esque no asignas ningun identificador para el objeto thread:
Código
  1. thread unHilo(newClient,socket_s,socket_c,client);

Mejor asi, no te olvides después hacer un join() antes de terminar.

Por cierto, los argumentos con referencia deben de indicarse con ref. De modo que debería ser así:
Código
  1. thread unHilo(newClient,ref(socket_s),ref(socket_c),ref(client));



Título: Re: Duda con threads
Publicado por: patilanz en 18 Mayo 2014, 17:19 pm
Gracias ahora funciona. La documentacion thread es algo mala en ningun lugar pone lo de ref()

Y una ultima pregunta  ;D
Puedo hacer join del thread desde la función que llama el thread?
Lo necesito porque tengo un thread que hace los listen pero tiene que ser multiusuario por lo tanto el thread no puede tener nombre ni me puedo parar a esperar para que el thread se cierre si no que se tiene que terminar solo con join cuando el usuario se valla, esto ya lo detecto con los sockets.


Título: Re: Duda con threads
Publicado por: ivancea96 en 18 Mayo 2014, 17:21 pm
Gracias ahora funciona. La documentacion thread es algo mala en ningun lugar pone lo de ref()

Y una ultima pregunta  ;D
Puedo hacer join del thread desde la función que llama el thread?
Lo necesito porque tengo un thread que hace los listen pero tiene que ser multiusuario por lo tanto el thread no puede tener nombre ni me puedo parar a esperar para que el thread se cierre si no que se tiene que terminar solo con join cuando el usuario se valla, esto ya lo detecto con los sockets.

http://www.cplusplus.com/reference/functional/ref/ (http://www.cplusplus.com/reference/functional/ref/)

Estoy seguro de que hay una forma mucho mejor de hacer lo que buscas. Si un thread se hace .join() a si mismo, no va a acabar ·_·


Título: Re: Duda con threads
Publicado por: amchacon en 18 Mayo 2014, 17:54 pm
Gracias ahora funciona. La documentacion thread es algo mala en ningun lugar pone lo de ref()

Y una ultima pregunta  ;D
Puedo hacer join del thread desde la función que llama el thread?
Lo necesito porque tengo un thread que hace los listen pero tiene que ser multiusuario por lo tanto el thread no puede tener nombre ni me puedo parar a esperar para que el thread se cierre si no que se tiene que terminar solo con join cuando el usuario se valla, esto ya lo detecto con los sockets.
Vamos a ver, me lees cuando escribo o que? :huh:
Citar
La clase thread presupone que harás join en algún momento (al final del programa/funcion normalmente), si tu idea es dejar el hilo a tu aire tienes que usar detach()

Código
  1. thread t(hilo);
  2. t.detach();

De todas formas, también puedes hacerlo con join(). Te haces un array de threads (al principio, vacios) y cuando sepas que un hilo se ha cerrado haces join (además de hacer join antes de cerrar el programa).


Título: Re: Duda con threads
Publicado por: patilanz en 18 Mayo 2014, 17:58 pm
Perdón no te había entendido lo de dejar al aire. Ahora ya todo esta perfecto.
Pero porque tengo que usar ref() cual es la diferencia en pasar lo por una función normal?
Gracias por tu paciencia


Título: Re: Duda con threads
Publicado por: ivancea96 en 18 Mayo 2014, 18:03 pm
Puedes evadir el ref() si en vez de  de parámetros SOCKET& los pones como SOCKET*, y pasas mediante &variable.


Título: Re: Duda con threads
Publicado por: amchacon en 18 Mayo 2014, 19:19 pm
Perdón no te había entendido lo de dejar al aire. Ahora ya todo esta perfecto.
Pero porque tengo que usar ref() cual es la diferencia en pasar lo por una función normal?
Gracias por tu paciencia
A mí por lo menos no me compila.

Son detalles de la implementación de la librería (no es como una llamada a función, es más complejo...). En tal caso, usa ref para pasarlos parametros por referencia en la clase thread. Además el código queda bastante autoexplicativo (se ve que paramétros son por valor y cuales por referencia).

Puedes evadir el ref() si en vez de  de parámetros SOCKET& los pones como SOCKET*, y pasas mediante &variable.
Y cada vez que tengas que adceder, con el * y los -> de marras. Quita, quita.

Los punteros son del pasado ^^


Título: Re: Duda con threads
Publicado por: ivancea96 en 18 Mayo 2014, 20:00 pm
Eso es para tu gusto e.e


Título: Re: Duda con threads
Publicado por: Eternal Idol en 19 Mayo 2014, 10:17 am
Los punteros son del pasado ^^

Te recomiendo Java y C#.


Título: Re: Duda con threads
Publicado por: eferion en 19 Mayo 2014, 10:23 am
Te recomiendo Java y C#.

Depende del uso... como necesites un algoritmo iterativo o recursivo con reservas de memoria en cada iteración... aunque luego las "liberes", te puedes encontrar con el caso de que el equipo se queda sin memoria en menos de un minuto... la razón es sencilla, al no tener tu control sobre el ciclo de vida sobre los objetos, éstos se quedan en estado latente esperando a ser eliminados por el recolector de basura... si tu aplicación no le da tiempo al recolector para trabajar, los objetos no se eliminan y la memoria se acumula hasta que te quedas sin nada.

Y no lo digo por decir, al menos en la versión 2.0 del framework de .Net es absurdamente sencillo... se puede hacer con bucles y clases de tipo string... no creo que las versiones posteriores hayan avanzado muchísimo en ese tema.

Moraleja: si el algoritmo o la aplicación hace un uso intensivo de memoria dinámica, .Net al menos ( y Java no creo que sea muy diferente ), no te sirven.


Título: Re: Duda con threads
Publicado por: Eternal Idol en 19 Mayo 2014, 10:35 am
Depende del uso... como necesites un algoritmo iterativo o recursivo con reservas de memoria en cada iteración... aunque luego las "liberes", te puedes encontrar con el caso de que el equipo se queda sin memoria en menos de un minuto... la razón es sencilla, al no tener tu control sobre el ciclo de vida sobre los objetos, éstos se quedan en estado latente esperando a ser eliminados por el recolector de basura... si tu aplicación no le da tiempo al recolector para trabajar, los objetos no se eliminan y la memoria se acumula hasta que te quedas sin nada.

Y no lo digo por decir, al menos en la versión 2.0 del framework de .Net es absurdamente sencillo... se puede hacer con bucles y clases de tipo string... no creo que las versiones posteriores hayan avanzado muchísimo en ese tema.

Moraleja: si el algoritmo o la aplicación hace un uso intensivo de memoria dinámica, .Net al menos ( y Java no creo que sea muy diferente ), no te sirven.

¿Y cual es la diferencia al fin y al cabo si pretendes no usar punteros en C++ tampoco? Entiendo que leiste a lo que respondi ...


Título: Re: Duda con threads
Publicado por: eferion en 19 Mayo 2014, 10:48 am
Si yo hago un bucle con strings sin usar punteros... en C++ tendré un uso bastante estable de la memoria.

En C# y Java usaré punteros sí o sí, solo que yo no voy a verlos como punteros porque esa parte la enmascara el framework... en este caso, el mismo ejemplo que con C++ resultará en un consumo absurdamente elevado de memoria hasta que el algoritmo termine y le de un respiro al recolector de basura para poder hacer su trabajo.


Título: Re: Duda con threads
Publicado por: Eternal Idol en 19 Mayo 2014, 11:14 am
Si yo hago un bucle con strings sin usar punteros... en C++ tendré un uso bastante estable de la memoria.

Código
  1. string p;
  2. for (int x = 0; x < 500; ++x)
  3.  p.insert(p.end(), 1024 * 1024, '.');
  4.  

Tal vez se me pierde el objetivo y/o sentido del bucle pero si hace algo que no se pierde inmediatamente ...


Título: Re: Duda con threads
Publicado por: eferion en 19 Mayo 2014, 11:27 am
Obviamente todos los almacenes de información a lo largo de un algoritmo implican un mayor consumo de recursos... en C, C++, C#, Java, Perl, PHP, ADA, Pascal, javascript y cualquier otro.

Sin embargo la cosa cambia cuando te encuentras con algo tal que:

Código
  1. #include <limits.h>
  2. #include <iostream>
  3.  
  4. int main( )
  5. {
  6.  for ( unsigned int i=0; i<UINT_MAX; i++ )
  7.  {
  8.    for ( unsigned int j = 0; j < UINT_MAX; j++ )
  9.    {
  10.      string variable = "ALGO" + std::to_string( i ) + std::to_string( j );
  11.      std::cout << variable << std::endl;
  12.    }
  13.  }
  14. }

Código
  1. public class Program
  2. {
  3.  public static void Main()
  4.  {
  5.    for ( uint i=0; i<uint.MaxValue; i++ )
  6.    {
  7.      for ( uint j = 0; j < uint.MaxValue; j++ )
  8.      {
  9.        string variable = "ALGO" + i.ToString( ) + j.ToString( );
  10.        System.Console.WriteLine( variable );
  11.      }
  12.    }
  13.  }
  14. }

Ya te garantizo yo que el consumo total de memoria del segundo programa en C# es bastante superior. Y cuando digo "bastante superior" me refiero descontando el consumo adicional de memoria que por defecto tiene C# con respecto a C++.


Título: Re: Duda con threads
Publicado por: amchacon en 19 Mayo 2014, 11:46 am
Te recomiendo Java y C#.
Esos no son punteros crudos al viejo C xD

Yo los situaría como las referencias de C++ (aunque estas se pueden modificar).


Título: Re: Duda con threads
Publicado por: Eternal Idol en 19 Mayo 2014, 12:03 pm
eferion: me debo estar perdiendo algo otra vez, ya que no se hace uso intensivo de la memoria dinamica (son unas cadenas de tamaño infimo) en tu ejemplo y se podria solventar facilmente usando una variable definida fuera del bucle en C# (acudo a la logica simplemente, no trabajo en .NET pero como el framework este medio bien hecho - tambien queda la JVM - al asignarle un nuevo puntero a variable deberia liberar la memoria anterior sin necesidad de recolectar basura posteriormente).

amchacon: por eso, si los punteros son el pasado ...


Título: Re: Duda con threads
Publicado por: amchacon en 19 Mayo 2014, 12:15 pm
amchacon: por eso, si los punteros son el pasado ...
En C++, el uso de punteros ya no es tan necesario. Para modificar variables y tal, prefiero mil veces las referencias.

El único uso que le veo a los punteros en C++ es para el polimorfismo. Para todo lo demás tienes las STL y las referencias:

Código
  1. unique_ptr<int> MemoriaDinamica(new int);
  2.  
  3. array<int,10> MemoriaDinamicaArray;
  4.  
  5. vector<int> MemoriaDinamicaVector(10);

Los punteros son suceptibles a los memoryleaks, las STL no ^^


Título: Re: Duda con threads
Publicado por: eferion en 19 Mayo 2014, 12:20 pm
Se hace uso intensivo de memoria porque cada vez que creas un string, en la versión de C# (igual pasaría con Java) se está creando bajo la figura de un puntero... cuando se sale del ámbito, la instancia de string se marca para ser reciclada por el recolector de basura. Dado que el proceso está ocupado con la ejecución del bucle, el recolector de basura no entra en juego... y eso sucede a lo largo de toda la vida del código que he puesto.

Resultado: 4 * 4,294,967,295^2 instancias de string esperando a ser liberadas... y ocupando espacio en memoria.

el 4 viene porque:

Código
  1. string variable = "ALGO" + i.ToString( ) + j.ToString( );

Esta línea implica la creación de 4 strings:

* primer string: "ALGO"
* segundo string: i.ToString( )
* tercer string: j.ToString( )
* cuarto string: variable = todo_lo_demas

Bueno, realmente creo que sería más correcto decir que en cada iteración se crean 5 strings... ya que los operadores de suma se resuelven uno a uno.

Citar
En C++, el uso de punteros ya no es tan necesario. Para modificar variables y tal, prefiero mil veces las referencias.

El único uso que le veo a los punteros en C++ es para el polimorfismo. Para todo lo demás tienes las STL y las referencias:

Los punteros son suceptibles a los memoryleaks, las STL no ^^

Totalmente de acuerdo.

Además, usando referencias evitas la tentación de hacer delete donde no corresponde :)


Título: Re: Duda con threads
Publicado por: Eternal Idol en 19 Mayo 2014, 12:32 pm
Tal vez un experto en .NET pueda resolver con facilidad este "problema". Es posible que no exista ninguna optimizacion ni en Java ni en C# como para resolver algo tan sencillo como que una variable temporal (todas las que no son variable que deberia poder ser liberada en cada iteracion con un cambio de ambito, cosa que podria ser aplicada a las demas variables temporales tambien llegado el caso) sea destruida inmediatamente pero me resulta dificil creerlo.



EDITO: acabo de probar tu codigo con el framework v2.0.50727 (el mas antiguo en mi maquina) el uso de memoria no aumenta ni siquiera por cada iteracion de i. "ALGO" no es un objeto segun ildasm.


Título: Re: Duda con threads
Publicado por: eferion en 19 Mayo 2014, 13:22 pm
Después de realizar algunas comprobaciones debo reconocer que .NET ha mejorado enormemente los problemas que comento.

Me apunto probar con strings más grandes... ya que el "tamaño" que ocupa uno de estos es francamente pequeño... y no se puede hacer un subclass de "string" porque es una clase "sealed".

Aún así me ha sorprendido la mejora de rendimiento al respecto.