Timer inifinite loop
-
Look at the code below, from first observation it looks fine. However, it gets into an infinite loop. This code synchronizes a file changes between two machines (A and B). Every time there is a change in the file on A the whole file has to be passed to machine B. (The file doesn't change on machine B). In order to avoid the network traffic on every change, there is a mechanism that passes the file only if didn't it change for the past last minute. The Scheduler is an external class that is used as a timer. When Scheduler::Schedule is called the scheduled method will be called every interval until the Scheduler::Unschedule is called. All the methods of MyClass (including the constructor) executes on the same thread!!!
// Header
class MyClass
{
public:
MyClass();
void FileChanged();
void PassFile();private:
long m_nTimerID;
Scheduler m_pScheduler;
};// Class
MyClass::MyClass()
{
m_nTimerID = 0;
m_pScheduler = new Scheduler();
}void MyClass::FileChanged()
{
if (0 != m_nTimerID)
{
// Unschedule the old timer
m_pScheduler->Unschedule(m_nTimerID);
}// This line will call to MyClass::PassFile every 60 seconds from now m\_nTimerID = m\_pScheduler->Schedule(60\*1000, &PassFile);
}
MyClass::PassFile()
{
if (0 != m_nTimerID)
{
// Unschedule the old timer
m_pScheduler->Unschedule(m_nTimerID);
m_nTimerID = 0;
}// Pass the file...
}
Try to find out what's causing the infinite loop. I'll post the answer later. Hint: I used the ACE::HeapTimer (I don't remember the exact class name) to implement the Scheduler class. Ami
-
Look at the code below, from first observation it looks fine. However, it gets into an infinite loop. This code synchronizes a file changes between two machines (A and B). Every time there is a change in the file on A the whole file has to be passed to machine B. (The file doesn't change on machine B). In order to avoid the network traffic on every change, there is a mechanism that passes the file only if didn't it change for the past last minute. The Scheduler is an external class that is used as a timer. When Scheduler::Schedule is called the scheduled method will be called every interval until the Scheduler::Unschedule is called. All the methods of MyClass (including the constructor) executes on the same thread!!!
// Header
class MyClass
{
public:
MyClass();
void FileChanged();
void PassFile();private:
long m_nTimerID;
Scheduler m_pScheduler;
};// Class
MyClass::MyClass()
{
m_nTimerID = 0;
m_pScheduler = new Scheduler();
}void MyClass::FileChanged()
{
if (0 != m_nTimerID)
{
// Unschedule the old timer
m_pScheduler->Unschedule(m_nTimerID);
}// This line will call to MyClass::PassFile every 60 seconds from now m\_nTimerID = m\_pScheduler->Schedule(60\*1000, &PassFile);
}
MyClass::PassFile()
{
if (0 != m_nTimerID)
{
// Unschedule the old timer
m_pScheduler->Unschedule(m_nTimerID);
m_nTimerID = 0;
}// Pass the file...
}
Try to find out what's causing the infinite loop. I'll post the answer later. Hint: I used the ACE::HeapTimer (I don't remember the exact class name) to implement the Scheduler class. Ami
Hi, Could you post Schedule(...) function code? If PassFile is callback function, initialized to be called from SetTimer() function, then it should be declared as static, and its proper definition look like this:
((CALLBACK* lpfnTimer)(HWND, UINT, UINT_PTR, DWORD)
Anyway, the m_nTimerID variable has to be passed by pointer, since use of non-static variables in static functions, is not supposed to happen. Regards -
Hi, Could you post Schedule(...) function code? If PassFile is callback function, initialized to be called from SetTimer() function, then it should be declared as static, and its proper definition look like this:
((CALLBACK* lpfnTimer)(HWND, UINT, UINT_PTR, DWORD)
Anyway, the m_nTimerID variable has to be passed by pointer, since use of non-static variables in static functions, is not supposed to happen. Regards -
Look at the code below, from first observation it looks fine. However, it gets into an infinite loop. This code synchronizes a file changes between two machines (A and B). Every time there is a change in the file on A the whole file has to be passed to machine B. (The file doesn't change on machine B). In order to avoid the network traffic on every change, there is a mechanism that passes the file only if didn't it change for the past last minute. The Scheduler is an external class that is used as a timer. When Scheduler::Schedule is called the scheduled method will be called every interval until the Scheduler::Unschedule is called. All the methods of MyClass (including the constructor) executes on the same thread!!!
// Header
class MyClass
{
public:
MyClass();
void FileChanged();
void PassFile();private:
long m_nTimerID;
Scheduler m_pScheduler;
};// Class
MyClass::MyClass()
{
m_nTimerID = 0;
m_pScheduler = new Scheduler();
}void MyClass::FileChanged()
{
if (0 != m_nTimerID)
{
// Unschedule the old timer
m_pScheduler->Unschedule(m_nTimerID);
}// This line will call to MyClass::PassFile every 60 seconds from now m\_nTimerID = m\_pScheduler->Schedule(60\*1000, &PassFile);
}
MyClass::PassFile()
{
if (0 != m_nTimerID)
{
// Unschedule the old timer
m_pScheduler->Unschedule(m_nTimerID);
m_nTimerID = 0;
}// Pass the file...
}
Try to find out what's causing the infinite loop. I'll post the answer later. Hint: I used the ACE::HeapTimer (I don't remember the exact class name) to implement the Scheduler class. Ami
the call to unschedule needs to be synchronized.
On two occasions I have been asked [by members of Parliament], 'Pray, Mr. Babbage, if you put into the machine wrong figures, will the right answers come out?' I am not able rightly to apprehend the kind of confusion of ideas that could provoke such a question. - Charles Babbage
-
the call to unschedule needs to be synchronized.
On two occasions I have been asked [by members of Parliament], 'Pray, Mr. Babbage, if you put into the machine wrong figures, will the right answers come out?' I am not able rightly to apprehend the kind of confusion of ideas that could provoke such a question. - Charles Babbage
-
The code doesn't run on the same thread. Call backs from timers are on seperate threads.
On two occasions I have been asked [by members of Parliament], 'Pray, Mr. Babbage, if you put into the machine wrong figures, will the right answers come out?' I am not able rightly to apprehend the kind of confusion of ideas that could provoke such a question. - Charles Babbage
-
The code doesn't run on the same thread. Call backs from timers are on seperate threads.
On two occasions I have been asked [by members of Parliament], 'Pray, Mr. Babbage, if you put into the machine wrong figures, will the right answers come out?' I am not able rightly to apprehend the kind of confusion of ideas that could provoke such a question. - Charles Babbage
The code is message based which is similar to Windows message loop. In Windows the GUI and the Timers are handled on the same thread. You can assume that the FileChanged method is called by a user button click. The click initiates a timer that its callback is called later on the same thread. However, synchronization is not an issue in the code. Ami
-
Look at the code below, from first observation it looks fine. However, it gets into an infinite loop. This code synchronizes a file changes between two machines (A and B). Every time there is a change in the file on A the whole file has to be passed to machine B. (The file doesn't change on machine B). In order to avoid the network traffic on every change, there is a mechanism that passes the file only if didn't it change for the past last minute. The Scheduler is an external class that is used as a timer. When Scheduler::Schedule is called the scheduled method will be called every interval until the Scheduler::Unschedule is called. All the methods of MyClass (including the constructor) executes on the same thread!!!
// Header
class MyClass
{
public:
MyClass();
void FileChanged();
void PassFile();private:
long m_nTimerID;
Scheduler m_pScheduler;
};// Class
MyClass::MyClass()
{
m_nTimerID = 0;
m_pScheduler = new Scheduler();
}void MyClass::FileChanged()
{
if (0 != m_nTimerID)
{
// Unschedule the old timer
m_pScheduler->Unschedule(m_nTimerID);
}// This line will call to MyClass::PassFile every 60 seconds from now m\_nTimerID = m\_pScheduler->Schedule(60\*1000, &PassFile);
}
MyClass::PassFile()
{
if (0 != m_nTimerID)
{
// Unschedule the old timer
m_pScheduler->Unschedule(m_nTimerID);
m_nTimerID = 0;
}// Pass the file...
}
Try to find out what's causing the infinite loop. I'll post the answer later. Hint: I used the ACE::HeapTimer (I don't remember the exact class name) to implement the Scheduler class. Ami
The code assumes that the
m_pScheduler->Schedule()
’s valid return values are greater than zero. This assumption is incorrect. After a few times theFileChanged
is called the method returns zero. The next time theFileChanged
is called it will not unscheduled the previous timer and will create a new one. The timer that was not scheduled goes into an infinite loop, because it will never get unscheduled. The first time I noticed the loop I didn’t understand how this could happen, but I added logs. The next time I saw it I could see by the logs why I get into the loop. To fix the code replace the 0 with –1, which is a really invalid timer id. Ami -
The code assumes that the
m_pScheduler->Schedule()
’s valid return values are greater than zero. This assumption is incorrect. After a few times theFileChanged
is called the method returns zero. The next time theFileChanged
is called it will not unscheduled the previous timer and will create a new one. The timer that was not scheduled goes into an infinite loop, because it will never get unscheduled. The first time I noticed the loop I didn’t understand how this could happen, but I added logs. The next time I saw it I could see by the logs why I get into the loop. To fix the code replace the 0 with –1, which is a really invalid timer id. AmiI think think then that -1 should be replaced with a constant defined in the scheduler that represents an error rather than a magic number.
On two occasions I have been asked [by members of Parliament], 'Pray, Mr. Babbage, if you put into the machine wrong figures, will the right answers come out?' I am not able rightly to apprehend the kind of confusion of ideas that could provoke such a question. - Charles Babbage
-
The code doesn't run on the same thread. Call backs from timers are on seperate threads.
On two occasions I have been asked [by members of Parliament], 'Pray, Mr. Babbage, if you put into the machine wrong figures, will the right answers come out?' I am not able rightly to apprehend the kind of confusion of ideas that could provoke such a question. - Charles Babbage
Depends on the type of timer. A
System.Windows.Forms.Timer
is implemented with theSetTimer
API, and therefore callbacks always occur on the UI thread (the one that created the form). ASystem.Threading.Timer
is implemented using waitable timers and will fire events on any available thread pool thread. It does not make any attempt to synchronise with a currently-running callback - it will fire off another event (on another thread) even if a previous callback has not yet returned. ASystem.Timers.Timer
wrapsSystem.Threading.Timer
and can be used to get back onto the appropriate thread for an object if you set theSynchronizingObject
property. It derives fromSystem.ComponentModel.Component
so it can be dropped onto designer surfaces.Stability. What an interesting concept. -- Chris Maunder