Bernardo Vieira Posted October 16, 2013 at 11:45 PM Report #529329 Posted October 16, 2013 at 11:45 PM (edited) Bom, o meu objetivo é fazer um codigo que chame uma callback a partir de um argumento de uma funcao, vou deixar o meu codigo abaixo. A minha ideia é chamar o teste1, ou teste2, ou teste3 e poder quebrar a chamada (timer) a qualquer momento. Nesse codigo esta tudo a funcionar correto, cria o timer, entretanto eu qubro o timer e depois ele responde que nao, ou seja ja nao esta ativo, só que eu queria que, quando estiver ativo ele chama-se o timer1 ou timer2, ou timer3. Isso seria indicado num argumento do settimer Alguem me sabe ajudar, Já nao é a primeira vez que tento fazer um codigo deste genero, mas sempre acabo por arrumar porque acho que nao tenho experiencia suficiente, mas desta vez gostaria mesmo de fazer, afinal de contas, esse codigo todo aí eu fiz em 10 minutos Obrigado a todos desde já para quem quiser ver o codigo com os tabs todos certos http://pastebin.com/iTZjR8PU #include <iostream> #include <unordered_map> #include <chrono> #include <thread> struct timers { bool ativo; int milliseconds; }; typedef std::unordered_map<int, struct timers*> map_time; map_time Map_Time; int t_time = 0; void teste1() { std::cout << "Ola" << std::endl; return; } void teste2(int id, char letra, char frase[]) { std::cout << id << " " << letra << " " << frase << std::endl; return; } void teste3(std::string frase, char letra, int id) { std::cout << frase.c_str() << " " << letra << " " << id << std::endl; return; } void virtual_time(timers* timer) { std::this_thread::sleep_for(std::chrono::milliseconds(timer->milliseconds)); if(timer->ativo) { std::cout << "Sim" << std::endl; } else { std::cout << "Nao" << std::endl; } return; } int settimer(int milliseconds) { struct timers* timer = (struct timers*) malloc(sizeof(struct timers)); memset(timer, 0, sizeof(struct timers)); timer->ativo = true; timer->milliseconds = milliseconds; Map_Time.insert(map_time::value_type(t_time,timer)); std::thread v_timer(virtual_time,timer); v_timer.detach(); return t_time; } bool killtimer(int timerid) { map_time::iterator j = Map_Time.find(timerid); if(j != Map_Time.end()) { struct timers* timer = (struct timers*) malloc(sizeof(struct timers)); memset(timer, 0, sizeof(struct timers)); timer = j->second; timer->ativo = false; Map_Time.erase(timerid); } return true; } int main() { std::cout << "Inicio" << std::endl; int timer = settimer(5000); std::this_thread::sleep_for(std::chrono::milliseconds(3000)); killtimer(timer); std::this_thread::sleep_for(std::chrono::milliseconds(3000)); system("pause"); return 1; } Edited October 16, 2013 at 11:49 PM by Bernardo Vieira
Flinger Posted October 17, 2013 at 09:02 AM Report #529343 Posted October 17, 2013 at 09:02 AM (edited) Não sei c++, mas o teu código está muito C, por isso vou arriscar meter o bedelho. Para declarares que uma função recebe uma callback, ou melhor, recebe um apontador para outra função, usas a sintaxe: void funcaoprincipal(tipoRetorno (*funcao_a_chamar) (tipos_argumento)) um exemplo prático, vamos por a tua função killtimer a receber a função teste2 como argumento: bool killtimer(int timerid, void (*funcao)(int,char,char*)) Para chamares a função killertime: killtimer (a,&teste2); Para chamares a calback dentro da função killtimer: funcao(a,b,c); No entanto, no teu caso existe um problema que por esta hora deves ter detectado. As tuas funções teste têm todas parâmetros diferentes... Não sei se poderás contornar isso usando variable arguments, mas a função que invoca a callback teria de detectar qual é a callback a chamar, e passar os argumentos correctos, o que mata o sentido de usar callbacks. Edited October 17, 2013 at 09:36 AM by Flinger 1 Report
pikax Posted October 17, 2013 at 09:03 AM Report #529344 Posted October 17, 2013 at 09:03 AM (edited) ve se isto ajuda-te: #include<stdio.h> #include<functional> #include<iostream> typedef void (*myCall) (int); void funccallback(int s) { std::cout<<"std::function: o numero igual="<<s<<std::endl; } void ccallback(int s) { std::cout<<"typedef C: o numero igual="<<s<<std::endl; } //C++ void ciclo(int b,int e, std::function<void(int)> fcall) { for(int i=b;i<e;i++) { fcall(i); } } void cicloC(int b,int e, myCall fcall) { for(int i=b;i<e;i++) { fcall(i); } } int main() { //C++ func std::function<void(int)> func = funccallback; ciclo(0,10,func); ciclo(0,10,ccallback); ciclo(0,10,[=](int s)-> void {std::cout<<"LambdaCall o numero igual="<<s<<std::endl;}); cicloC(0,10,ccallback); cicloC(0,10,[=](int s)-> void {std::cout<<"LambdaCall o numero igual="<<s<<std::endl;}); } http://ideone.com/29T0fb http://ideone.com/29T0fb Edited October 17, 2013 at 09:03 AM by pikax 1 Report Por muito mais que que estude só aprendo uma coisa, que ainda tenho muita coisa para aprender. A beleza de um código está em decompor problemas complexos em pequenos blocos simples. "learn how to do it manually first, then use the wizzy tool to save time." "Kill the baby, don't be afraid of starting all over again. Fail soon, learn fast."
HappyHippyHippo Posted October 17, 2013 at 09:30 AM Report #529346 Posted October 17, 2013 at 09:30 AM (edited) existe 2º razões para a minha solução : - C++ - independência da assinatura do callback class Timer { public: virtual ~Timer() {} virtual void callback(void) = 0; } class MyTimer : public Timer { public: MyTimer(/* os parâmetros que queiras */int param1, std::string param2) : _param1(param1), _param2(param2) { } virtual ~MyTimer() {} virtual void callback(void) { std::cout << "param1 = " << this->_param1 << std::endl; std::cout << "param2 = " << this->_param2 << std::endl; } protected: int _param1; std::string _param2; } Timer * my_timer = new MyTimer(2, "string"); // agora é só chamar a função de callback my_timer->callback(); conclusão : só tens de gerir a instância MyTimer apontada pelo ponteiro my_timer struct timers { bool ativo; int milliseconds; Timer * timer; // <--- onde vais guardar a instância da tua classe }; int settimer(int milliseconds, Timer * timer) { // ... timer->ativo = true; timer->milliseconds = milliseconds; timer->timer = timer; // ... } void virtual_time(struct timers* timer) { // <--- falta o struct // ... if(timer->ativo) { timer->timer->callback(); // <---- chamada do callback } // ... } no entanto, como foi dito, esse código está muito C-style, e não verifiquei se isso corre mesmo como um timer ------------------------------------------------------------------------------------------- exemplo completo e funcional em C++ #include <iostream> #include <unordered_map> #include <chrono> #include <thread> #include <cstring> class Timer { public: Timer(int delta) : _thread(NULL), _active(true), _run(false), _delta(delta) {} virtual ~Timer() { this->stop(); } virtual void callback(void) = 0; bool isActive(void) { return this->_active; } bool isRunning(void) { return this->_run; } int getDelta(void) { return this->_delta; } void setDelta(int delta) { this->_delta = delta; } void activate(void) { this->_active = true; } void deactivate(void) { this->_active = false; } void run(void) { if (this->_thread == NULL) { this->_run = true; this->_thread = new std::thread(Timer::proc, this); } } void stop(void) { this->_run = false; if (this->_thread != NULL) { this->_thread->join(); this->_thread = NULL; } } protected: static void proc(Timer * timer) { bool running; do { std::this_thread::sleep_for(std::chrono::milliseconds(timer->getDelta())); running = timer->isRunning(); if (running && timer->isActive()) { timer->callback(); } } while (running); } protected: std::thread * _thread; bool _active; bool _run; int _delta; }; class MyTimer : public Timer { public: MyTimer(int delta, int param1, std::string param2) : Timer(delta), _param1(param1), _param2(param2) { } virtual ~MyTimer() {} virtual void callback(void) { std::cout << "param1 = " << this->_param1 << std::endl; std::cout << "param2 = " << this->_param2 << std::endl; } protected: int _param1; std::string _param2; }; int main() { std::cout << "Inicio" << std::endl; Timer * timer = new MyTimer(1000, 1, "string"); timer->run(); std::this_thread::sleep_for(std::chrono::milliseconds(10000)); delete timer; std::cout << "Fim" << std::endl; return 0; } Edited October 17, 2013 at 01:44 PM by HappyHippyHippo 2 Report IRC : sim, é algo que ainda existe >> #p@p Portugol Plus
Bernardo Vieira Posted October 17, 2013 at 06:58 PM Author Report #529482 Posted October 17, 2013 at 06:58 PM (edited) Desde já um grande obrigado aos 3 🙂 mas responderam um bocadinho da forma que eu ja sabia fazer... na verdade eu quero é fazer um sistema que chame uma callback, seja lá qual for o nome dela e independetemente dos valores, tipo, podia ter som int, ou int, char, int ou char, char, int enfim, sem uma regra exata. Mas bom, todos me ajudaram mais um pouco, e desculpem-me o facto de estar muito em estilo C, eu uso sempre o VSC++ e acabo por me esquecer desse pormenor. @Flinger, dessa forma eu também sei fazer, mas obrigado @pikax, interessante por acaso, acho que vou conseguir o que quero com uma pequena modificacao nisso. Obrigado @HappyHippyHippo sim, ainda aprendi umas coisas 😛 só que eu queria independencia de parametros tambem ... Mas muito obrigado Mais uma vez obrigado a todos 🙂 Edited October 17, 2013 at 07:03 PM by Bernardo Vieira
HappyHippyHippo Posted October 17, 2013 at 07:03 PM Report #529484 Posted October 17, 2013 at 07:03 PM na verdade eu quero é fazer um sistema que chame uma callback, seja lá qual for o nome dela e independetemente dos valores, tipo, podia ter som int, ou int, char, int ou char, char, int enfim, sem uma regra exata. e onde é que o meu exemplo invalida isso ? ao contrário das outras soluções que estás limitado a essa mesma permissa (isto sem o uso das variadic functions como o @Flinger referiu) IRC : sim, é algo que ainda existe >> #p@p Portugol Plus
Bernardo Vieira Posted October 17, 2013 at 07:06 PM Author Report #529486 Posted October 17, 2013 at 07:06 PM Entao foi eu que nao entendi corretamente o teu codigo :|
pikax Posted October 17, 2013 at 07:13 PM Report #529489 Posted October 17, 2013 at 07:13 PM soluções que estás limitado a essa mesma permissa nao tem muito nexo teres um timer que vai chamar uma callback com argumentos que nao conheces, a menos que passes para o timer quais sao os argumentos para essa funcao... mesmo assim seria uma ma' implementacao, se necessitas de chamar uma callback com N de argumentos deveras usar uma lambda! Por muito mais que que estude só aprendo uma coisa, que ainda tenho muita coisa para aprender. A beleza de um código está em decompor problemas complexos em pequenos blocos simples. "learn how to do it manually first, then use the wizzy tool to save time." "Kill the baby, don't be afraid of starting all over again. Fail soon, learn fast."
HappyHippyHippo Posted October 17, 2013 at 07:18 PM Report #529490 Posted October 17, 2013 at 07:18 PM (usando o código acima) queres um callback use dois int's e uma string ? class MyTimer2 : public Timer { public: MyTimer2(int delta, int param1, int param2, std::string param3) : Timer(delta), _param1(param1), _param2(param2), _param3(param3) { } virtual ~MyTimer2() {} virtual void callback(void) { // ... do stuff ... } protected: int _param1; int _param2; std::string _param3; }; // ... Timer * timer = new MyTimer2(1000, 1, 2, "string"); timer->run(); queres um callback use int int's e uma string e um vector de doubles ? class MyTimer3 : public Timer { public: MyTimer3(int delta, int param1, std::string param2, std::vector<double> param3) : Timer(delta), _param1(param1), _param2(param2), _param3(param3) { } virtual ~MyTimer3() {} virtual void callback(void) { // ... do stuff ... } protected: int _param1; std::string _param2; std::vector<doubles> _param3; }; // ... Timer * timer = new MyTimer3(1000, 1, "string", new std::vector<doubles>()); timer->run(); como vês, os parâmetros são dados na criação do timer. podes usar o que quiseres ... IRC : sim, é algo que ainda existe >> #p@p Portugol Plus
Bernardo Vieira Posted October 17, 2013 at 07:33 PM Author Report #529494 Posted October 17, 2013 at 07:33 PM @pikax nao é propriamente desconhecido @HappyHippyHippo ahh, entao eu tendi certo, pensei que tavas era a dizer outra coisa Voce ainda nao entenderam, eu queria fazer algo do genero MyTimer(nomecallback[], intervalo, fomatacao[], argumentos); com os valores MyTimer("teste2", 5000,"ics", 5, 'a', "ja funciona"); ou MyTimer("teste3", 5000,"sci", "ja funciona", 'a', 5); (teste2 e teste3 referem-se ao meu primeiro codigo) ou seja, uma callback, um tempo e a seguir parametros, a minha duvida é, como é que eu chamo a callback, porque o par de parametros talvez eu consiga!
pikax Posted October 17, 2013 at 08:58 PM Report #529514 Posted October 17, 2013 at 08:58 PM (edited) como vês, os parâmetros são dados na criação do timer. podes usar o que quiseres ... a menos que passes para o timer quais sao os argumentos para essa funcao esse tipo de implementacao nao e' a melhor devido que o timer fica limitado devido ao facto que teres que criar uma class derivada do timer sempre que queres um tipo de timer diferente... class DelegateTimer : public Timer { public: MyTimer(std::function<void(void)> func) _func(func){ } virtual ~MyTimer() {} virtual void callback(void) { _func(); } protected: std::function<void(void)> _func; }; void myFunction(std::string str, int start, int end) { ///......etc... } //.... Timer * timer = new DelegateTimer([]->{ myFunction("Xenx",0,10);}); timer->run(); int i = 1234; int b = 12344; std::string ddd = "P@P"; //memory leak timer = new DelegateTimer([&]-> { for (int a = 0; a < 50; ++a) { std::cout<<ddd<<i<<b<<std::endl; } } ); timer->run(); btw nem se deveria usar threads, usar promisses seria o mais correcto neste caso. EDIT: Utilizar lambdas para criar um wrapper numa funcao, e' a forma mais flexivel de criar uma callback, para mais ele em principio nao ira' querer o valor de retorno da callback ou ja' sabera' quais serao os argumentos que a funcao ira' ter. Edited October 17, 2013 at 09:01 PM by pikax 1 Report Por muito mais que que estude só aprendo uma coisa, que ainda tenho muita coisa para aprender. A beleza de um código está em decompor problemas complexos em pequenos blocos simples. "learn how to do it manually first, then use the wizzy tool to save time." "Kill the baby, don't be afraid of starting all over again. Fail soon, learn fast."
Bernardo Vieira Posted October 17, 2013 at 09:33 PM Author Report #529520 Posted October 17, 2013 at 09:33 PM wow .... bem, mais uma vez obrigado, era isso mesmo, vou usar como exemplo ^^ obrigado 🙂
HappyHippyHippo Posted October 17, 2013 at 10:11 PM Report #529527 Posted October 17, 2013 at 10:11 PM btw nem se deveria usar threads, usar promisses seria o mais correcto neste caso. porque ? não existe necessidade de garantia de retorno de valor nenhuma das funções de callback apresentada retorna uma valor sequer IRC : sim, é algo que ainda existe >> #p@p Portugol Plus
pikax Posted October 17, 2013 at 11:00 PM Report #529532 Posted October 17, 2013 at 11:00 PM (edited) porque ? não existe necessidade de garantia de retorno de valor mas ha' a necessidade de garantia que seja exception-safe, alem do mais se fizeres spawns a +10 timers, iras ter muitas threads a gastar concorrerem entre si pelo CPU. nenhuma das funções de callback apresentada retorna uma valor sequer por isso mesmo e' que nao existe necessidade de criar uma class derivada sempre que queres uma callback com argumentos diferentes Edited October 17, 2013 at 11:01 PM by pikax Por muito mais que que estude só aprendo uma coisa, que ainda tenho muita coisa para aprender. A beleza de um código está em decompor problemas complexos em pequenos blocos simples. "learn how to do it manually first, then use the wizzy tool to save time." "Kill the baby, don't be afraid of starting all over again. Fail soon, learn fast."
HappyHippyHippo Posted October 18, 2013 at 05:54 AM Report #529550 Posted October 18, 2013 at 05:54 AM mas ha' a necessidade de garantia que seja exception-safe existe ? alem do mais se fizeres spawns a +10 timers, iras ter muitas threads a gastar concorrerem entre si pelo CPU. 10 threads não é nada principalmente quando a função principal e um sleep IRC : sim, é algo que ainda existe >> #p@p Portugol Plus
Bernardo Vieira Posted October 18, 2013 at 01:02 PM Author Report #529600 Posted October 18, 2013 at 01:02 PM (edited) Bom, mais uma vez obrigado a todos, e com uma coisa aqui outra ali, sempre consegui fazer o que queria. deiam uma olhada http://pastebin.com/ZCjAZuqa a grande vantagem é que eu nao preciso dizer qual é a callback nem quais sao os argumentos, nada, ou seja, agora, vou criar uma pequena callback, e passar o std::bind por typename e já funcionará corretamente, ou acham melhor usar tipo #define ? bom, eu lembrei-me do bind porque ele aparece no boost e como o C++11 tras muitas coisas do boost, acabei por me lembrar Este codigo é uma versao de teste, mas funciona, já agora gostaria de saber a vossa opiniao, á algo que deva mudar para melhorar ? Abraço para todos 🙂 Edited October 18, 2013 at 01:03 PM by Bernardo Vieira
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now