timesetevent in mehreren Objekten - Timer blockieren sich



  • Hiho,

    ich hab folgendes Problem:

    In einer Anwendung können mehrere Objekte einer Klasse angelegt werden.
    Jedes dieser Objekte startet einen Timer mit timeSetEvent (Windows Multimediatimer).
    Wenn nur ein Objekt erzeugt wird, läuft der Timer wunderbar. Alles funktioniert.
    Gibt es jetzt aber mehrere Objekte, die jeweils mit timeSetEvent ihren Timer starten(mit unterschiedlichen Perioden) blockieren sich die timer gegenseitig, d.h. erst wird die Callback von ersten Timer aufgerufen und erst wenn sie fertig ist, die callback vom zweiten. Die Timer laufen sozusagen aufeinander auf, denn sobald die erste Callback fertig ist, kommt gleich danach die zweite, weil der zweite Timer während der Ausführung der ersten Callback abgelaufen ist.
    (Die Timer werden erst nach Abarbeitung der Callback wieder neu gestartet. )

    Da timesetevent als veraltet markiert ist, habe ich auch die neue Funktion CreateTimerQueueTimer verwendet, geht aber ebenso wenig, obwohl es da besondere Flags gibt, wie z.B. WT_EXECUTEINTIMERTHREAD

    Ich brauche unter Windows VS C++ einen Timer, der pro Objekt völlig unabhängig läuft. Wenn also die Callback von obj1 blockiert ist, muss die Callback von obj2 unbeeindruckt weitermachen.
    Ich habs mal mit Threads anstelle von Timern probiert, da klappts wunderbar.
    Aber das ist ja nicht so doll.

    Ich habe mal ein kleines Beispiel gemacht, wo die Problematik auftritt.
    Ich weiß, dass der Programmierstil nicht gut ist, aber es zeigt auf die Schnelle das Problem.
    Bei Punkt 1. und 2. werden die Callbacks immer nacheinander ausgeführt und nicht parallel.
    Ist ein Windows Consolenprogramm:

    #include "stdafx.h"
    #include "timerDummy.h"
    #include <string>
    #include "NeuerTimer.h"
    #include "ThreadLösung.h"
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	int ende;
    
    	//1.Normaler Multimediatimer mit timeSetEvent
    	//timerDummy timer1 = timerDummy(1, 1000);
        //timerDummy timer2 = timerDummy(2, 2500);
    
    	//2.TimerQueue
    	NeuerTimer timer1 = NeuerTimer(1,1000);
    	NeuerTimer timer2 = NeuerTimer(2,2500);
    
    	//3.Lösung mit Threads
    	/*ThreadLösung timer1 = ThreadLösung(1,1000);
    	ThreadLösung timer2 = ThreadLösung(2,2500);*/
    
    	std::cin>> ende;
    
    	timer1.kill();
    	timer2.kill();
    
    	system("Pause");
    	return 0;
    }
    
    #pragma once
    class timerDummy
    {
    public:
    	timerDummy(int id, int period);
    	~timerDummy(void);
    	void arbeiteWas();
    	void kill();
    
    private:
    	 int mId;
    	 MMRESULT m_mmTimerID;
    	 int m_period;
    	 bool m_stop;
    };
    
    #include "StdAfx.h"
    #include "timerDummy.h"
    #include <string>
    
    void CALLBACK TimerFkt(UINT uTimerID, unsigned int uMsg,DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2)
    {
    	((timerDummy*) dwUser)->arbeiteWas();
    }
    
    timerDummy::timerDummy(int id, int period)
    {
    	mId = id;
    	m_period = period;	
    	m_mmTimerID = timeSetEvent(period, 0,  (LPTIMECALLBACK)&TimerFkt , (DWORD_PTR)this , TIME_CALLBACK_FUNCTION |  TIME_ONESHOT  | TIME_KILL_SYNCHRONOUS);				 
    	m_stop = false;
    }
    
    timerDummy::~timerDummy(void)
    {
    }
    
    void timerDummy::arbeiteWas()
    {
    	std::cout<<"1 Timer Dummy:" << mId<<std::endl;
    	Sleep(1000);
    	std::cout<<"2 Timer Dummy:" << mId<<std::endl;
    	Sleep(1000);
    	std::cout<<"3 Timer Dummy:" << mId<<std::endl;
    	Sleep(1000);
    	std::cout<<"4 Timer Dummy:" << mId<<std::endl;
    
    	if(!m_stop)
    	{
    		m_mmTimerID = timeSetEvent(m_period, 0,  (LPTIMECALLBACK)&TimerFkt , (DWORD_PTR)this , TIME_CALLBACK_FUNCTION | TIME_ONESHOT | TIME_KILL_SYNCHRONOUS);		
    	}
    }
    
    void timerDummy::kill()
    {
    	m_stop = true;
         MMRESULT res=timeKillEvent(m_mmTimerID);
    }
    
    #pragma once
    
    class NeuerTimer
    {
    public:
    	NeuerTimer(int id, int period);
    	~NeuerTimer(void);
    
    	void tuWas();
    	void kill();
    
    private:
    	int mId;
    	HANDLE newTimerHandle;
    	HANDLE timerQueue1, timerQueue2;
    	int m_period;
    	bool m_stop;
    };
    
    #include "StdAfx.h"
    #include "NeuerTimer.h"
    
    void CALLBACK TimerProc(void* lpParameter, BOOLEAN TimerOrWaitFired)
    {
    	((NeuerTimer*) lpParameter)->tuWas();
    }
    
    NeuerTimer::NeuerTimer(int id, int period)
    {
    	mId = id;
    	m_period = period;
    	m_stop = false;
    	timerQueue1 = CreateTimerQueue();
    
    	CreateTimerQueueTimer(&newTimerHandle, timerQueue1, TimerProc, this,period, 0,  WT_EXECUTEINPERSISTENTTHREAD|WT_EXECUTEONLYONCE);
    }
    
    NeuerTimer::~NeuerTimer(void)
    {
    }
    
    void NeuerTimer::tuWas()
    {
    	std::cout<<"1 Timer Dummy ID:" << mId<<std::endl;
    	std::cout<<"2 Timer Dummy ID :" << mId<<std::endl;
    	Sleep(1000);
    	std::cout<<"3 Timer Dummy ID:" << mId<<std::endl;
    	Sleep(1000);
    	std::cout<<"4 Timer Dummy ID:" << mId<<std::endl;
    
    	if(!m_stop)
    	{
    		CreateTimerQueueTimer(&newTimerHandle, timerQueue1, TimerProc, this, m_period, 0, WT_EXECUTEINPERSISTENTTHREAD|WT_EXECUTEONLYONCE);
    	}
    
    }
    void NeuerTimer::kill()
    {
    	m_stop = true;
    	DeleteTimerQueueTimer(timerQueue1,newTimerHandle, NULL);
    }
    
    #pragma once
    class ThreadLösung
    {
    public:
    	ThreadLösung(int id, int period);
    	~ThreadLösung(void);
    	bool Start_eines_threads();
    	void tuWas();
    	void kill();
    
    private:
    	unsigned int anzahl_threads; //die anzahl an gerade benutzten threads
              HANDLE       hConsoleOut; //Handle für die console 
    
    	CONSOLE_SCREEN_BUFFER_INFO csbiInfo;//Konsolen information
    	int mId;
    	uintptr_t newTimerHandle;
    	int m_period;
    	bool m_stop;
    };
    
    #include "StdAfx.h"
    #include "ThreadLösung.h"
    
    void thread_test( void *pMyID )
    {
    	((ThreadLösung*)pMyID)->tuWas();
    }
    
    ThreadLösung::ThreadLösung(int id, int period)
    {
    	anzahl_threads=0;
              hConsoleOut = GetStdHandle( STD_OUTPUT_HANDLE );
             GetConsoleScreenBufferInfo( hConsoleOut, &csbiInfo );
             mId = id;
    	m_period = period;
    	m_stop = false;
    	Start_eines_threads();
    }
    
    ThreadLösung::~ThreadLösung(void)
    {
    }
    
    bool ThreadLösung::Start_eines_threads()
    {
       anzahl_threads++;
       newTimerHandle = _beginthread(thread_test,0,&anzahl_threads);
       return true;
    }
    
    void ThreadLösung::tuWas()
    {
    	while(m_stop == false)
    	{
    	std::cout<<"1 Thread Dummy:" << mId<<std::endl;
    	Sleep(500);
    	std::cout<<"2 Thread Dummy:" << mId<<std::endl;
    	Sleep(500);
    	std::cout<<"3 Thread Dummy:" << mId<<std::endl;
    	Sleep(1000);
    	std::cout<<"4 Thread Dummy:" << mId<<std::endl;
    
              Sleep(m_period);
    	}
    
    }
    void ThreadLösung::kill()
    {
       m_stop = true;
    }
    


  • Du könntes in deinem Callback einen Semaphor eines Objektes setzen.
    Diser Callback würde den Timer nur kurz blockieren.

    Für deine Objekte startest du jeweils einen Thread.
    In den Thread wartest du dann immer bis der entsprechente Semaphor freigegeben wird.


Log in to reply