Notice the title: This article doesn't provide accurate information about Windows process management, but my own guess.
I first used Windows 3.x in 1997. I did't have a computer and I did't have much chance to use a computer so I didn't get much knowledge of Windows 3.x at that time. I was interested in physics and I wondered why Windows 3.x can make multiple applications run at the same time.
During the three years when I was in my senior high school, I learned something about Windows 3.x and Windows 98, and I also learned some special behavior of both operating systems.
Since Windows 3.x is much simpler than later Windows operating systems, I started looking into the system. I found the multi-tasking of the system is called collaborative multi-tasking (is it accurate in English, I mean the Chinese phrase "xietong shi duo renwu"). Collaborative multi-tasking is based on collaboration between applications. Applications must have an idea that they are working together, and everybody must ensure that he himself doesn't keep the CPU for too long.
For example, if you are using a word processor, and there is a media player playing music in the background, the CPU flow is like this: You type a character in the word processor, Windows tells the WP (word processor) by adding a message in the message queue of the WP. The WP asks Windows to dispatch the message to the correct window of it and then translates the message. Then Windows discovered that the WP has a message to deal with and call the corresponding window procedure, which is binded with the message receiver window of the WP. The window procedure records the character you typed and refreshes the display, and then returns to Windows. Windows finds the next application appropriate to run and runs it. Suppose the application is the media player (MP). The MP checks whether it is time to load a new block of media data to memory and send it to the hardware device that processes the data (for example, the sound card that processes wave data). If yes, do it. If no, return to Windows.
In the example above, we see that the media player loads a block of data when necessary. What would happen if it goes on waiting until the next block of data can be loaded? The word processor would lose reponse. The word processor couldn't be run. This means the media player can only use a piece of time that is short enough so that other applications can be run in time.
It is quite fussy when the application that really does a continuous job. For example, an application that calculates PI. This might be a long job, but the programmer has to divide the operation into pieces in order to run properly in the collaborative multi-tasking environment. The programmer can add a variable that records the number of times of basic operations, each of which takes a short fixed CPU time, and when the variable reaches a particular value, suspend current work and return to Windows. However, checking the value of the variable consumes time. If the programmer wants to reduce useless time consumption, he/she should make a detailed approximation upon the time layout of the program. Of course this is a tiresome job.
How does Windows jump between processes when multi-tasking? It can be done using the C language and assembly language. For example (pseudo code): add_message(); /* external */ switch(); /* external */ get_message(); /* internal */ dispatch_message(); /* internal */ wndproc1(); wndproc2(); wndproc3(); /* internal */ ... It seems that switch() requires assembly, since it needs to change the current task.
Windows 9x/NT OSes don't have this drawback as I disussed in my article Windows 95 Multi-tasking.
There are worker threads and window threads in Windows 95. Worker threads are suitable for continuous jobs. Window threads are suitable for displaying windows or exchanging messages.
In my imagination, an application or Windows sends a message to a window, then the message is stored in the message queue of the corresponding window thread. When Windows decides that the application is in turn to run, Windows helps the application translate a message and dispatch it to the correct window. Then Windows call the corresponding window procedure. On one of two situations the application suspends or returns: If the application successfully did the job in time, it returns to Windows. If the application failed to return in time, it is automatically suspended by Windows. The job is done through a system timer interrupt.
In MINIX, all system calls are done through messaging. There is a problem when the application makes a system call. It should be hung up and then resumed. Of course this can be achieved, but what if the application received a message during the call? If the application deals with the message, there may be potential data sharing conflict. How to avoid this? I think an easy way is to make the message-processing function re-entrant.
Back to Windows. There is a strange thing in the code of Windows applications: When the application starts a modal dialog, the code seem to be calling a modal dialog function (such as DialogBox() or DoModal()). Then what? The message processor function seems to be hung up, but actually, the window still responds to messages: it is automatically redrawn, etc. What happened? It seems that the previous windows processor function which called the dialog function is suspended (blocked), and all its data are kept (those in the stack), but another stack is allocated for new message processor function calls. When the old message processor function (which called the dialog function) is exits, Windows should free the corresponding stack segment. Is it funny? We should notice that Windows wouldn't let more than one message processor function run except when one of them are blocked. In Year 2010, when I worked at Microsoft, I accidentally found the answer to the question when I debugged an application. It's that the inner level calls inside the DialogBox() API has a message loop! There, it dispatches messages, so other messages can still be processed while the original one is blocked.
Since Windows 95, multi-threading is supported. This means one program can have multiple threads run at the same time. This allows simpler programming on programs that processes data in background and responds to the user in foreground. To share data safely in multi-threading programs, system level semaphores or something similar should be used to serialize data sharing. If a program wants to communicate to another program, the program should use IPC (interprocess communication) system services.
Windows records process ID, program location, memory allocation and so on for each running application. These information help Windows run applications properly.