C++/Dual Control Problem
For my class project, i have made a program. But now I realise that i have to run 2 functions, at the same time. First to keep track of the system time. Second to do something every second. But how do i run the 2 functions at the same time?
This is an interesting and complex question so I am going to have to give you an overview and let you research the areas that interest you. Then please feel free to ask more specific questions.
The short answer is don't if you do not have to. If you think about it you do not have to if all you need to keep track of the time for is to know when to schedule the next call to the do-something function:
While 1 second has not elapsed
In fact this is about all you can do using the standard C++ facilities. It is also extremely dumb as it wastes system resources - you will probably knock your processing up to 100% running an implementation of the above program outline (unless you have two or more processors or processor cores). A better version would be:
Suspend program for 1 second
This is a much better way to behave on a modern pre-emptive multitasking operating system such as Windows XP or Linux/UNIX.
Now a little background. Modern desktop and server operating systems execute programs in processes. Depending on the operating system a process may have one or more threads of execution. Initially a process would have one thread of execution. Each thread of execution basically allows the system to be doing one thing at a time.
An operating system that uses pre-emptive multitasking can suspend execution of any executing thread (or process depending on the design of the operating system) at any point in its execution and start executing another. This is controlled by the operating system scheduler. I shall assume for the rest of the answer that threads are the units of execution scheduled by an operating system and that a process is a collection of threads running in their own virtual memory space. This is the 32-bit Windows model (Windows NT/2000/XP, 95/98/ME). At any given moment the system can be executing one thread per processor or processor core. All other threads are suspended. Threads typically have a priority and a time-slice. The priority is used to determine which suspended thread(s) are most eligible to execute next when a currently executing thread is suspended. The time slice is the amount of time a thread can actually spend executing before it will be pre-empted for another thread should no higher priority thread become ready for execution in the mean time. A thread can become suspended during its execution for several reasons other than being pre-empted. It can be waiting on an I/O operation to complete or it could be waiting for some event to occur or another thread to relinquish control of a resource or other threads to catch up with it.
One common way a thread can suspend itself is an operation usually called sleep or similar. Such functions typically take an argument for the amount of time to sleep for. The units and types used for these values differ. The Win32 API function Sleep() takes a value representing the number of milliseconds. The UNIX/Linux sleep() function on the other hand takes a value in seconds. So on a Win32 system you can suspend your program's thread of execution for one second using Sleep(1000), and on a UNIX or Linux system by calling sleep(1) (note: UNIX/Linux typically schedule processes). You can find the Win32 API function described in the MSDN library, online at http://msdn.microsoft.com/library/
. The UNIX/Linux sleep function is described in the man pages for sleep, which can be found online at various places, for example http://unixhelp.ed.ac.uk/CGI/man-cgi?sleep+3
Now you may find that your program does not always respond on an exact 1 second interval. This is because all the scheduler does is mark your thread read for execution. When it gets around to actually allowing it to execute depends on what else the system is doing.
This is all very well, but none of this is part of C or C++. In fact C and C++ do not recognise processes and threads. Hence support has to come from the operating system or third party libraries that wrap the raw operating system functionality such as the Boost thread library - see http://www.boost.org/
Now what if you really do wish to have two parallel threads of execution. The answer is to create a second thread. You typically pass the new thread a function for it to execute. The thread will terminate when the function returns, so you typically have a loop in the thread function.
Once you start to use more than one thread you come up against a nasty facet of such programming - you need to carefully synchronise access to shared resources between the two threads. Again the facilities available and the exact interfaces they use are operating system or third party library dependent. Common synchronisation facilities are locks, mutexes, semaphores and condition variables. I am not going to go into them here in much detail as a proper explanation will require much too much space than I have here (AllExperts answers are restricted to 10000 characters). The basic idea is that if a variable is shared by more than one thread then you will have to prevent more than one thread updating and possibly accessing it at the same time. The problem is that you will find that decisions are often based on the value of such variables and certain combinations of decisions and updates have to be done by one thread from the start to the end to leave the program in a valid state. Such sections of code are called critical (or possibly atomic) and forcing only one thread to access such sections of code is called serialisation. The object used to synchronise threads through such sections of code is often called a mutex (for mutual exclusion) or critical section. Locking a mutex or critical section will either allow a thread access to the critical section of code or will suspend the thread until the mutex/critical section object is unlocked.
I find it best to read the description of such facilities for the library or API I am using at the time to see if they can help me in the situation at hand.
If this has left you reeling then you are not alone. Multithreaded programming is hard. Getting correct is hard. Debugging is hard because most multithread related problems are timing related and debugging typically alters the timing of the code being executed e.g. by breaking and single stepping though 1 thread of execution. If you do not get it correct then there is always some combination of thread execution sequencing that will cause problems and trying to think your way through the possibilities can give you a headache <g>!
If that has left you scared to use threads I will say that in some simple cases you can probably get away without too many headaches. However you might be able to simulate the effects to some degree by using a reactive environment. In such an environment your code reacts to signals or events or messages. A good example is a Windows (or MacOS or X windowing system) GUI program. In such programs you provide handlers that react to the messages sent to your application. Windows for example has a timer message WM_TIMER and you can schedule a timer to go off after a specified amount of time. So in your application you would request WM_TIMER messages to be sent at 1 second intervals. The do-something function would be called as the handler for the WM_TIMER message. If you were using the Microsoft Foundation Classes (MFC) to build your Windows GUI application then maybe in some window class you would set the timer going, in the handler for some button click maybe:
UINT const TimerId(1);
m_TimerId = TimerId;
m_TimerId = SetTimer(m_TimerId, 1000, NULL );
KillTimer( m_TimerId ); // stop timer.
void MyDialog::OnTimer( UINT_PTR nIDEvent )
// Do Something
I have used both multiple threads and a reactive enironment to achieve the effect of doing more than one thing at a time. The only thing about using the reactive environment is that the work had to be cut into small chunks so that each time the do-something timer handler was called it did not hang up the program for too long from the user's point of view as there is only a single thread of execution. However as you planned to call your do-something function at regular intervals I presume it does not do too much work anyway. The plus side is that all the synconisation hassle goes away. However like thread and related facilities, these enviromnets are non-standard to C and C++ and require use of operating system or 3rd party library specific facilities.
Again, this has beed an overview of the sort of options available to you. If you have more speciifc questions then please ask.