|
|
1.1 root 1: /*************************************************************************\
2: * PROGRAM: Sema.c
3: *
4: * PURPOSE:
5: *
6: * To demonstrate controlling multiple threads through the use of a
7: * semaphore.
8: *
9: * FUNCTIONS:
10: *
11: * WinMain() - Initializes the window, and process the message loop.
12: * MainWndProc() - Process messages, creates semaphore and threads.
13: *
14: * GLOBAL VARIABLES:
15: *
16: * - hWnd: Handle to the window.
17: * - hSemaphore:
18: * Handle of the semaphore used between the threads.
19: *
20: * COMMENTS:
21: *
22: * To Use:
23: * Start the application. You will see five rectangles: a dynamic
24: * rectangle in the center (always changing color), and four static
25: * rectangles surrounding it. Each of the four rectagles has their
26: * own color: red, blue, green, and gray. The one in the center
27: * alternates between these colors.
28: *
29: * The four static rectangles represent four threads. These four
30: * threads compete for the rectangle in the middle, and their access
31: * is controlled by the semaphore. When the thread gains control of
32: * the semaphore, it gets to draw it's color in the center rectangle.
33: * (note: the threads do not actually draw any of the four static
34: * rectangles. To make the code simpler this is handled in the
35: * WM_PAINT message in the MainWndProc(). They are only meant as
36: * a visual representation of the threads. The threads do however
37: * draw the rectangle in the center with their specific color.)
38: *
39: * What Happens:
40: * The semaphore has a use count. When it is set to zero, any thread
41: * can access the semaphore and execute the code within its "semaphore
42: * gate" by using WaitForSingleObject(). When the thread gains
43: * control of the semaphore usint this call, the use count is
44: * incremented by one. When the thread is done executing its code,
45: * it can call ReleaseSemaphore(). This will decrement the count
46: * by what ever value you indicate (this code uses 1) signalling
47: * to any other thread that it may gain control of the semaphore.
48: *
49: * Note that any thread which has access to the semaphore may decrement
50: * its use count with ReleaseSemaphore(); the thread does not have
51: * to have control of the semaphore at the time.
52: *
53: * In this code, the WM_CREATE message in MainWndProc creates a
54: * semaphore. The four threads are then created, each waiting
55: * on the semaphore .
56: *
57: * Each of the threads loop, blocking on a WaitForSingleObject()
58: * call. Once any thread has set the use count to 0, the thread
59: * gets to draw draw the center rectagle with its color, and then
60: * sleeps for half a second before freeing the semaphore again.
61: * The thread then runs through the loop again.
62: *
63: \*************************************************************************/
64: #include <windows.h>
65: #include <stdlib.h>
66: #include "sema.h"
67:
68:
69: HANDLE hInst;
70: HANDLE hWnd;
71: HANDLE hSemaphore;
72:
73: /*************************************************************************\
74: *
75: * FUNCTION: WinMain(HANDLE, HANDLE, LPSTR, int)
76: *
77: * PURPOSE: calls initialization function, processes message loop
78: *
79: * COMMENTS:
80: *
81: \*************************************************************************/
82: int APIENTRY WinMain (HANDLE hInstance,
83: HANDLE hPrevInstance,
84: LPSTR lpCmdLine,
85: int nCmdShow)
86: {
87: MSG msg;
88: WNDCLASS wc;
89:
90: UNREFERENCED_PARAMETER( lpCmdLine );
91: UNREFERENCED_PARAMETER( hPrevInstance );
92:
93: hInst = hInstance;
94:
95: wc.style = CS_VREDRAW | CS_HREDRAW;
96: wc.lpfnWndProc = (WNDPROC)MainWndProc;
97: wc.cbClsExtra = 0;
98: wc.cbWndExtra = 0;
99: wc.hInstance = hInstance;
100: wc.hIcon = LoadIcon (NULL, IDI_APPLICATION);
101: wc.hCursor = LoadCursor (NULL, IDC_ARROW);
102: wc.hbrBackground = GetStockObject (WHITE_BRUSH);
103: wc.lpszMenuName = "";
104: wc.lpszClassName = "SemaWClass";
105:
106: RegisterClass(&wc);
107:
108:
109: hWnd = CreateWindow ("SemaWClass",
110: "Semaphore Sample",
111: WS_OVERLAPPEDWINDOW,
112: CW_USEDEFAULT,
113: CW_USEDEFAULT,
114: CW_USEDEFAULT,
115: CW_USEDEFAULT,
116: NULL,
117: NULL,
118: hInstance,
119: NULL);
120:
121:
122: ShowWindow(hWnd, nCmdShow);
1.1.1.2 ! root 123: while (GetMessage (&msg, NULL, 0, 0))
1.1 root 124: DispatchMessage (&msg); // Dispatch message to window.
125:
126: return (msg.wParam); // Returns value from PostQuitMessage.
127:
128: }
129:
130: /*************************************************************************\
131: *
132: * FUNCTION: MainWndProc (HWND, UINT, UINT, LONG)
133: *
134: * PURPOSE: To process the windows messages. This procedure creates
135: * the semaphore and the four threads. It also draws the
136: * four static rectangles.
137: *
138: * VARIABLES USED:
139: *
140: * - hThread?:
141: * These four static varaibles are handles to the four
142: * created threads.
143: *
144: * - ThreadID?:
145: * These four variables are local DWORDS used in the
146: * CreateThread() call.
147: *
148: * - pColor?:
149: * These four variables are used as pointers to memory
150: * which is allocated and filled with color values to
151: * pass as a parameter to each of the threads (so the
152: * threads know what color they are to paint the rectangle).
153: *
154: * - Paint: A paint structure used in BeginPaint() and EndPaint().
155: *
156: * - rect: A RECT structure used to get the windows client area.
157: * It's needed to figure out the new relative positions
158: * of the four static rectangles when the user resizes
159: * the window.
160: *
161: * - Col?, Row?, width, height:
162: * These local DWORDs are used to position the four static
163: * rectangles and to determin their size.
164: *
165: * - hDC: Handle to the DC for the window.
166: *
167: * - hBrush:
168: * Handle to a brush, used to set the color of the four static
169: * rectangles.
170: *
171: * MESSAGES:
172: *
173: * WM_CREATE: - Creates a semaphore; allocates some
174: * memory and sets it with color values to be passed
175: * as parameter values to the threads. It then
176: * creates four threads, giving each its own color.
177: *
178: * WM_PAINT: - Checks the size of the client space and then
179: * draws the four static rectangles to their relative
180: * positions.
181: *
182: * WM_DESTROY: - Terminates the threads, and posts a quit message.
183: *
184: * CALLED BY:
185: *
186: * WinMain();
187: *
188: * CALLS TO:
189: *
190: * ThreadProc();
191: *
192: \*************************************************************************/
193:
194:
195: LONG APIENTRY MainWndProc (HWND hwnd,
196: UINT message,
197: UINT wParam,
198: LONG lParam)
199: {
200: DWORD ThreadID1, ThreadID2, ThreadID3, ThreadID4;
201: RECT rect;
202: DWORD Col1, Col2, Col3, Row1, Row2, Row3, width, height;
203: HDC hDC;
204: HANDLE hBrush;
205: PAINTSTRUCT Paint;
206: static HANDLE hThread1, hThread2, hThread3, hThread4;
207: static DWORD *pColor1, *pColor2, *pColor3, *pColor4;
208: CHAR Buf[80];
209:
210:
211: switch (message)
212: {
213:
214: case WM_PAINT:
215: hDC = BeginPaint (hwnd, &Paint);
216: GetClientRect( hWnd, &rect); // Get window rectangle.
217:
218: width = rect.right / 4; // Calculate static rectangle's
219: height = rect.bottom / 4; // width and height.
220:
221: Col1 = (rect.right / 16) * 1; // Calculate x positions.
222: Col2 = (rect.right / 16) * 6;
223: Col3 = (rect.right / 16) * 11;
224: // Calculate y positions.
225: Row1 = (rect.bottom / 16) * 1;
226: Row2 = (rect.bottom / 16) * 6;
227: Row3 = (rect.bottom / 16) * 11;
228:
229: hBrush = CreateSolidBrush((COLORREF)RED);
230: SelectObject (hDC, hBrush);
231: Rectangle (hDC, Col2, Row1, Col2+width, Row1+height);
232: DeleteObject (hBrush);
233: // Draw the Blue rectangle.
234: hBrush = CreateSolidBrush((COLORREF)BLUE);
235: SelectObject (hDC, hBrush);
236: Rectangle (hDC, Col1, Row2, Col1+width, Row2+height);
237: DeleteObject (hBrush);
238: // Draw the Green rectangle.
239: hBrush = CreateSolidBrush((COLORREF)GREEN);
240: SelectObject (hDC, hBrush);
241: Rectangle (hDC, Col2, Row3, Col2+width, Row3+height);
242: DeleteObject (hBrush);
243: // Draw the Gray rectangle.
244: hBrush = CreateSolidBrush((COLORREF)GRAY);
245: SelectObject (hDC, hBrush);
246: Rectangle (hDC, Col3, Row2, Col3+width, Row2+height);
247: DeleteObject (hBrush);
248:
249: EndPaint (hwnd, &Paint);
250: return (0);
251:
252: case WM_CREATE :
253: // Create the semaphore.
254: hSemaphore = CreateSemaphore (NULL, 0, 1, NULL);
255:
256: if (!hSemaphore)
257: {
258: wsprintf (Buf, "CreateSemaphore() Error = %d",
259: GetLastError());
260: MessageBox(hwnd, Buf, "WM_CREATE", MB_OK);
261: return (0);
262: }
263:
264: pColor1 = malloc(sizeof(DWORD));
265: *pColor1 = GREEN; // Create the Green thread.
266: hThread1 = CreateThread (NULL, 0,
267: (LPTHREAD_START_ROUTINE)ThreadProc,
1.1.1.2 ! root 268: (LPVOID)pColor1, 0,
1.1 root 269: (LPDWORD)&ThreadID1);
270:
271: pColor2 = malloc(sizeof(DWORD));
272: *pColor2 = RED; // Create the Red thread.
273: hThread2 = CreateThread (NULL, 0,
274: (LPTHREAD_START_ROUTINE)ThreadProc,
1.1.1.2 ! root 275: (LPVOID)pColor2, 0,
1.1 root 276: (LPDWORD)&ThreadID2);
277:
278: pColor3 = malloc(sizeof(DWORD));
279: *pColor3 = BLUE; // Create the Blue thread.
280: hThread3 = CreateThread (NULL, 0,
281: (LPTHREAD_START_ROUTINE)ThreadProc,
1.1.1.2 ! root 282: (LPVOID)pColor3, 0,
1.1 root 283: (LPDWORD)&ThreadID3);
284:
285: pColor4 = malloc(sizeof(DWORD));
286: *pColor4 = GRAY; // Create the Gray thread.
287: hThread4 = CreateThread (NULL, 0,
288: (LPTHREAD_START_ROUTINE)ThreadProc,
1.1.1.2 ! root 289: (LPVOID)pColor4, 0,
1.1 root 290: (LPDWORD)&ThreadID4);
291:
292: ReleaseSemaphore (hSemaphore, 1, NULL);
293:
294: return (0);
295:
296:
297: case WM_DESTROY : // Terminate the threads and
298: TerminateThread(hThread1, 0); // clean up.
299: TerminateThread(hThread2, 0);
300: TerminateThread(hThread3, 0);
301: TerminateThread(hThread4, 0);
302: free (pColor1);
303: free (pColor2);
304: free (pColor3);
305: free (pColor4);
306:
307: PostQuitMessage (0);
308: return (0);
309:
310: }
311: return DefWindowProc (hwnd, message, wParam, lParam);
312: }
313:
314:
315: /*************************************************************************\
316: *
317: * FUNCTION: ThreadProc (LPVOID)
318: *
319: * PURPOSE: A thread procedure which requests a semaphore, and then
320: * draws it's color to the rectangle in the middle of the
321: * window.
322: *
323: * VARIABLES USED:
324: *
325: * - Color: An input parameter, a pointer to a DWORD with a color
326: * value in it.
327: *
328: * - rect: The RECT rectangle of the client window, needed to know where
329: * the center rectangle resides.
330: *
331: * - hDC: Handle to the DC of the window.
332: *
333: * - hBrush:
334: * Handle to a brush, used to set the rectangle's color to the
335: * threads.
336: *
337: * - width, height, Col, Row:
338: * DWORDs use to position the rectangle.
339: *
340: * CALLED BY:
341: *
342: * MainWndProc();
343: *
344: \*************************************************************************/
345: VOID ThreadProc ( LPVOID *Color)
346: {
347: RECT rect;
348: HDC hDC;
349: HANDLE hBrush;
350: DWORD width, height, Col, Row;
351:
352: hBrush = CreateSolidBrush((COLORREF)*Color);
353:
354: do
355: {
356: WaitForSingleObject (hSemaphore, INFINITE);
357: GetClientRect( hWnd, &rect);
358:
359: width = rect.right / 4;
360: height = rect.bottom / 4;
361: Col = (rect.right / 16) * 6;
362: Row = (rect.bottom / 16) * 6;
363:
364: hDC = GetDC(hWnd);
365: SelectObject( hDC, hBrush);
366: Rectangle (hDC, Col, Row, Col + width, Row + height);
367: ReleaseDC(hWnd, hDC);
368: Sleep (500);
369: ReleaseSemaphore (hSemaphore, 1, NULL);
370:
371: }while(1);
372: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.