Llamadas de función asíncrona -- ++ campo con multithreading camp codereview Relacionados El problema

Asyncronous Function Calls


4
vote

problema

Español

Estoy escribiendo una biblioteca de C ++ inspirada en nodo.js para llamadas de función asíncrona.

¿Qué tan eficiente y estable se ve mi código?

Si lo desea, puede ver un código de WIP y el código de demostración aquí . (net.hpp es para sockets posix y está lejos de ser hecho. No tiene ninguna función IO escrita)

  /* ASYNC.HPP  * Defines some functions for calling other functions in the background  * This gives the ability to create callback based functions easily,  * similar to node.js (But I hate javascript so I wrote this library for c++)  */  #ifndef ASYNC_H #define ASYNC_H #include <thread> #include <vector>  std::vector<std::thread> asyncCalls; // Don't have to deal with threads leaving scope since this vector is global #define asyncCall asyncCalls.emplace_back // Whenever someone calls asyncCall this constructs a new std::thread which calls their function  void finishAsync(){ //Call to block until all running asyncronous functions return while(!asyncCalls.empty()){ //Loop until the vector is empty         asyncCalls.back().join(); //Get the thread from the back and join it to block                 //^ I feel like this line might throw an exception, but in my testing it hasn't thrown anything.         asyncCalls.pop_back(); //Pop it and get a new one } } // Infinite running threads will block forever  #ifdef _GLIBCXX_CHRONO //Include <chrono> before this header for this function  void sleep(uint32_t millis){ //I just realized while adding comments that I could do this with a define. Oh well     std::this_thread::sleep_for(std::chrono::milliseconds(millis)); }  #endif // End chrono function  #endif //End header guard   
Original en ingles

I am writing a node.js inspired C++ library for asynchronous function calls.

How efficient and stable does my code look?

If you want, you can see some WIP code and demonstration code here. (net.hpp is for POSIX sockets and is far from done. It does not have any IO functions written)

/* ASYNC.HPP  * Defines some functions for calling other functions in the background  * This gives the ability to create callback based functions easily,  * similar to node.js (But I hate javascript so I wrote this library for c++)  */  #ifndef ASYNC_H #define ASYNC_H #include <thread> #include <vector>  std::vector<std::thread> asyncCalls; // Don't have to deal with threads leaving scope since this vector is global #define asyncCall asyncCalls.emplace_back // Whenever someone calls asyncCall this constructs a new std::thread which calls their function  void finishAsync(){ //Call to block until all running asyncronous functions return while(!asyncCalls.empty()){ //Loop until the vector is empty         asyncCalls.back().join(); //Get the thread from the back and join it to block                 //^ I feel like this line might throw an exception, but in my testing it hasn't thrown anything.         asyncCalls.pop_back(); //Pop it and get a new one } } // Infinite running threads will block forever  #ifdef _GLIBCXX_CHRONO //Include <chrono> before this header for this function  void sleep(uint32_t millis){ //I just realized while adding comments that I could do this with a define. Oh well     std::this_thread::sleep_for(std::chrono::milliseconds(millis)); }  #endif // End chrono function  #endif //End header guard 
     
 
 

Lista de respuestas

6
 
vote
vote
La mejor respuesta
 
  std::vector<std::thread> asyncCalls;   

Esto crea una variable global (por lo tanto, usted sabe, no hagas eso ) "y crea la variable global en cada archivo .CPP que importa este archivo de encabezado. Por lo tanto, a menos que solo tenga un archivo .cpp en su proyecto, obtendrá errores enlazadores cuando intente vincular su proyecto.

Lo que quería hacer fue poner esta definición de variable en un archivo .cpp y poner una declaración de ella (usando 9988776655544331 ) en su archivo .HPP.

Alternativamente, a partir de C ++ 17, podría haberlo hecho un 99887776655544332 Variable:

  inline std::vector<std::thread> asyncCalls;   

Sin embargo, las variables globales son terribles; No hagas nada como esto. Tal vez lo que quiera es una idea de "Piscina de hilo":

  class ThreadPool {     std::vector<std::thread> asyncCalls;     // ... };   

  #define asyncCall asyncCalls.emplace_back // Whenever someone calls asyncCall this constructs a new std::thread which calls their function   

Esta es una macro de preprocesador (por lo tanto, usted sabe, no haga eso ). Lo que querías decir fue

  class ThreadPool {     std::vector<std::thread> asyncCalls;  public:     template<typename... Args>     void asyncCall(Args&&... args) {         asyncCalls.emplace_back(std::forward<Args>(args)...);     } };   

  void finishAsync(){ //Call to block until all running asyncronous functions return while(!asyncCalls.empty()){ //Loop until the vector is empty   

DOS COSAS:

  • Por favor, indique su código. Los sangrías de cuatro espacios serían agradables.

  • ¿A quién esperas llamar a esta función? ¿Y cómo sabe que nadie más va a llamar emplace_back en el mismo instante de que ese tipo está llamando 9988777665544339 ? Parece que tiene un gran problema de seguridad de hilo aquí.


  extern0  

no hagas esto. Por un lado, su código no va a hacer lo correcto en el clang con libc ++ (o MSVC, o básicamente cualquier distribución no libstdc ++). Lo que querías decir fue

  extern1  

De esta manera, su encabezado incluye todos los encabezados que depende, recursivamente, y nunca tiene que preocuparse por si su persona que llama incluyó otra cosa antes de usted o no.


En cuanto al "Código sería una buena idea si funcionara": un rotundo no. su función no está haciendo nada que extern3 no haría por sí solo; y extern4 por sí solo es una mala idea porque si lo llama demasiadas veces, eventualmente se quedará sin hilos y comenzará a obtener errores "recurso temporalmente agotado". Si va a estar escribiendo programas que usan asínchrony como su técnica de implementación principal, la última cosa que desea hacer es quedarse sin hilos. Debe descubrir alguna forma de hacer cola de "Tareas" sin atar todo un 99887776655443315 por (estancado) Tarea.

 
std::vector<std::thread> asyncCalls; 

This creates a global variable (so, you know, don't do that) xe2x80x94 and it creates the global variable in every .cpp file that imports this header file. So unless you only have one .cpp file in your project, you're going to get linker errors when you try to link your project.

What you wanted to do was put this variable definition in a .cpp file and put a declaration of it (using extern) in your .hpp file.

Alternatively, as of C++17, you could have made it an inline variable:

inline std::vector<std::thread> asyncCalls; 

However, global variables are terrible; don't do anything like this. Maybe what you want is some notion of "thread pool":

class ThreadPool {     std::vector<std::thread> asyncCalls;     // ... }; 

#define asyncCall asyncCalls.emplace_back // Whenever someone calls asyncCall this constructs a new std::thread which calls their function 

This is a preprocessor macro (so, you know, don't do that). What you meant was

class ThreadPool {     std::vector<std::thread> asyncCalls;  public:     template<typename... Args>     void asyncCall(Args&&... args) {         asyncCalls.emplace_back(std::forward<Args>(args)...);     } }; 

void finishAsync(){ //Call to block until all running asyncronous functions return while(!asyncCalls.empty()){ //Loop until the vector is empty 

Two things:

  • Please indent your code. Four-space indents would be nice.

  • Who do you expect to call this function? and how do you know that nobody else is going to be calling emplace_back at the same instant that that guy is calling empty? Looks like you have a huge thread-safety problem here.


#ifdef _GLIBCXX_CHRONO //Include <chrono> before this header for this function 

Don't do this. For one thing, your code won't do the right thing on Clang with libc++ (or MSVC, or basically any non-libstdc++ distribution). What you meant was

#include <chrono> 

This way, your header includes all the headers it depends on, recursively, and you never have to worry about whether your caller included something else before you or not.


As far as "would this code be a good idea if it worked": a resounding no. Your asyncCall function isn't really doing anything that std::async wouldn't do on its own; and std::async on its own is a bad idea because if you call it too many times you'll eventually run out of threads and start getting "Resource temporarily exhausted" errors. If you're going to be writing programs that use asynchrony as their primary implementation technique, the last thing you want to do is run out of threads. You need to figure out some way to queue up "tasks" without tying up a whole std::thread per (stalled) task.

 
 
   
   

Relacionados problema

4  Programador de tareas de flujo  ( Flow task scheduler ) 
escenario : Quería un programador de tareas / Duende que permite que mi aplicación programe algunas tareas que se ejecuten en un tiempo específico pero e...

5  Contando letras lo más rápido posible  ( Counting letters as quickly as possible ) 
Recibí una tarea, de tomar un archivo de texto conocido (Diccionario de Linux), use hilos para contar las diferentes letras en ella y presentar los resultados...

2  Programa de productores / consumidores  ( Producer consumer program ) 
Soy un programador de Java semi-nuevo que tiende a ser un perfeccionista. Lo que me gustaría saber sobre mi código: cómo se compara con la práctica común. ...

5  Alcanzar un objeto grande en el entorno multithreading  ( Caching large object in multithreading environment ) 
Estoy teniendo que desbordarse con el almacenamiento en caché y el multithreading (hilo por solicitud), y soy un principiante absoluto en esa área, por lo que...

6  Un pequeño módulo para manejar actualizaciones de texto  ( A tiny module for handling text updates ) 
Llame a estas actualizaciones de texto "Feeds". Un objeto Feed tiene algunos atributos básicos como su cadena de contenido, cuántas vidas tiene y su priorid...

4  Conexión a la red Haskell Handler agraciado  ( Haskell network connection graceful handler ) 
Simplemente tratando de resolver un simple código de manejo de conexiones elegante en Haskell para obtener la cabeza alrededor de algunas de las cosas de IO /...

2  Cola de bloqueo delimitada  ( Bounded blocking queue ) 
¿Puede alguien por favor revise este código para mí? No he implementado todos los métodos para la simplicidad. NSUSerDefaults1 Preguntas abiertas: l...

8  Prueba de registro multithread  ( Multithreaded log test ) 
Estoy escribiendo una extensión de registrador que permite que varios subprocesos registren un proceso, y luego voltee ese registro en el registro principal e...

3  Generador de imágenes de Mandelbrot con iteración paralela  ( Mandelbrot image generator with parallel iteration ) 
Actualmente estoy tratando de optimizar esta clase que tengo para la generación fractal. La ecuación está destinada a ser conectable; He usado z => z*z + c ...

2  Prealización de memoria multi-roscada  ( Multi threaded memory preallocation ) 
Necesito averiguar la mejor manera de lidiar con la asignación previa a la memoria A continuación se muestra el pseudo-código para lo que estoy haciendo aho...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos