This is the first example of a book "The beauty of programming" compiled by Microsoft's Asia Research Institute.
The result is to draw a sine curve for the CPU utilization of the Windows Task Manager. Below is:
I. Principles
By observing, the CPU utilization curve in the task manager is refreshed once every second. The average value of each second is drawn and connected to the previous vertex. If the program is executed for 0.5 seconds within one second and sleep for 0.5 seconds, the curve for this second will be located at 50%. To draw a sine curve, we only need to calculate the height (relative to 0) of the point on the curve in each second, and then adjust the running and sleep time by adjusting the time, to draw the line of the second.
II. Specific implementation
First, we define some constants. The first one is Pi = 3.14159265, which will be used to calculate the trigonometric value later. The second, Count = 200, is used to record the positions of all vertices. You can change the value to a greater value, so that the plotting is more accurate. Third, split = 0.01. Calculate the step size of the trigonometric function. Similarly, the smaller the value, the more accurate it is. Fourth, interval = 300, time interval.
We need two arrays, busyspan [] and idlespan []. It is used to store the "busy" Time and "idle" time respectively. The following code records all the changes of the sine value in a cycle.
For (INT I = 0; I <count; I ++) <br/> {<br/> busyspan [I] = (DWORD) (Half + (sin (pI * radian) * Half); <br/> idlespan [I] = interval-busyspan [I]; <br/> radian + = split; <br/>}
Then start running. We use a starttime to record the start time of a cycle. Before each loop, we use the gettickcount function to record the start time. And constantly compare whether the running time of the current cycle has exceeded the pre-calculated busyspan. If the time exceeds, use the sleep function to sleep the program's idlespan time. In this way, we can draw a cycle. The Code is as follows:
DWORD starttime = 0; <br/> Int J = 0; <br/> while (true) <br/> {<br/> J = J % count; <br/> starttime = gettickcount (); <br/> while (gettickcount ()-starttime <= busyspan [J]) <br/>; <br/> sleep (idlespan [J]); <br/> J ++; <br/>}
The code above applies only to a single CPU. on multiple (or multiple cores) CPUs, the Operating System Schedules processes to different CPUs according to certain rules, in this way, the sine curve cannot be drawn. Therefore, we must first determine whether the user's computer has multiple CPUs.
Use the getsysteminfo function to obtain system information and pass the system_info structure to the function. A member dwnumberofprocessors in the structure indicates the number of processors. If the value is greater than or equal to 2, multiple processors exist. We need to use the setprocessaffinitymask function to set the relevance of the current process and ensure that it runs on a certain CPU.
The setprocessaffinitymask function accepts two parameters. The first parameter is the process handle, which is opened using the OpenProcess function, and the second parameter is a mask. Each bit indicates a CPU starting from the low position. If 0x00000005 is passed, it indicates 1st and 3rd CPUs. Here we pass 0x00000001, and it runs on the first CPU. The Code is as follows:
System_info Si; <br/> zeromemory (& Si, sizeof (SI); </P> <p> getsysteminfo (& Si); <br/> If (SI. dwnumberofprocessors >=2) <br/>{< br/> handle hproc = OpenProcess (process_all_access, false, getcurrentprocessid (); <br/> setprocessaffinitymask (hproc, 0x00000001); <br/>}
Don't forget to close the process handle before the program ends.
Of course, it would be better if the curve can be drawn simultaneously on multiple CPUs. The implementation method is very simple. Create multiple threads, each thread occupies one CPU, and then draw their own. The implementation code is as follows:
Handle hthread [8]; <br/> for (INT I = 0; I <= ncpu-1; I ++) <br/>{< br/> hthread [I] = NULL; <br/> hthread [I] = createthread (null, null, & draw, null, create_suincluded, null); <br/> setthreadaffinitymask (hthread [I], power (2, I); <br/> resumethread (hthread [I]); <br/>}< br/> waitformultipleobjects (ncpu, hthread, true, infinite );
First, create a handle array to store all the thread handles. because the number of CPUs on most computers does not exceed 8, an array of 8 elements is defined. Use the createthread function to create a thread. Pay attention to passing create_suincluded. First, suspend the thread and then set its relevance. The thread function draw is the curve drawn above. Power is a function defined by myself. It is used to calculate the power B of A. Because the POW function provided by the system is of the double type, it is a bit difficult to use. Fill the mask variable with the n integer of 2 to rewrite the n-bit of the lower byte to 1. Then the thread is restored.
After exiting the loop, use waitformultipleobjects to wait for each thread to work.
3. Related Links
Microsoft Visual C ++ 2008 SP1 redistributable package (x86) (from Microsoft official website)
Iv. References
The beauty of Programming Group, the beauty of programming, Electronic Industry Press
Microsoft Development Network
V. Remarks
If the above text and related code have bugs or are worthy of improvement, please notify the author. You can reply below, you can also send me an email: chenxinyu_hero@163.com
Ver 1, 20100811