多线程中的volatile关键字

注:多线程中由于线程间需要同步,线程可能会不断检查某个同步值的是否改变,这必然牵涉到循环。由于编译器的优化,在循环中它不会每次都检查同步值。这就需要volatile关键字来说明这个同步值,告诉编译器不要对其进行优化。下面的程序源码摘自《Windows程序设计第五版》相关章节。

关键字:多线程 同步 循环监测 volatile 编译优化

/*----------------------------------------

BIGJOB1.C -- Multithreading Demo

(c) Charles Petzold, 1998

----------------------------------------*/

#include <windows.h>

#include <math.h>

#include <process.h>

#define REP 10000000 //Translator: the original value 1000000 is too small, increase 10 times to be 10000000

#define STATUS_READY 0

#define STATUS_WORKING 1

#define STATUS_DONE 2

#define WM_CALC_DONE (WM_USER + 0)

#define WM_CALC_ABORTED (WM_USER + 1)

typedef struct

{

HWND hwnd ;

BOOL bContinue ;

}

PARAMS, *PPARAMS ;

LRESULT APIENTRY WndProc (HWND, UINT, WPARAM, LPARAM) ;

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,

PSTR szCmdLine, int iCmdShow)

{

static TCHAR szAppName[] = TEXT ("BigJob1") ;

HWND hwnd ;

MSG msg ;

WNDCLASS wndclass ;

wndclass.style = CS_HREDRAW | CS_VREDRAW ;

wndclass.lpfnWndProc = WndProc ;

wndclass.cbClsExtra = 0 ;

wndclass.cbWndExtra = 0 ;

wndclass.hInstance = hInstance ;

wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;

wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;

wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;

wndclass.lpszMenuName = NULL ;

wndclass.lpszClassName = szAppName ;

if (!RegisterClass (&wndclass))

{

MessageBox (NULL, TEXT ("This program requires Windows NT!"),

szAppName, MB_ICONERROR) ;

return 0 ;

}

hwnd = CreateWindow (szAppName, TEXT ("Multithreading Demo"),

WS_OVERLAPPEDWINDOW,

CW_USEDEFAULT, CW_USEDEFAULT,

CW_USEDEFAULT, CW_USEDEFAULT,

NULL, NULL, hInstance, NULL) ;

ShowWindow (hwnd, iCmdShow) ;

UpdateWindow (hwnd) ;

while (GetMessage (&msg, NULL, 0, 0))

{

TranslateMessage (&msg) ;

DispatchMessage (&msg) ;

}

return msg.wParam ;

}

void Thread (PVOID pvoid)

{

double A = 1.0 ;

INT i ;

LONG lTime ;

volatile PPARAMS pparams ;

/* 注意Thread中的pparams变量定义为volatile,这种型态限定字向编译器指出:该变量可能会在实际的程序叙述外被修改(例如被另一个线程)。 否则, 最佳化的编译器会假设pparams->bContinue不能被for循环内的程序代码修改,没有必要在每层循环中检查变量。volatile关键词防止这样的最佳化进行。 */

pparams = (PPARAMS) pvoid ;

lTime = GetCurrentTime () ;

for (i = 0 ; i < REP && pparams->bContinue ; i++)

A = tan (atan (exp (log (sqrt (A * A))))) + 1.0 ;

if (i == REP)

{

lTime = GetCurrentTime () - lTime ;

SendMessage (pparams->hwnd, WM_CALC_DONE, 0, lTime) ;

}

else

SendMessage (pparams->hwnd, WM_CALC_ABORTED, 0, 0) ;

_endthread () ;

}

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)

{

static INT iStatus ;

static LONG lTime ;

static PARAMS params ;

static TCHAR * szMessage[] = { TEXT ("Ready (left mouse button begins)"),

TEXT ("Working (right mouse button ends)"),

TEXT ("%d repetitions in %ld msec") } ;

HDC hdc ;

PAINTSTRUCT ps ;

RECT rect ;

TCHAR szBuffer[64] ;

switch (message)

{

case WM_LBUTTONDOWN:

if (iStatus == STATUS_WORKING)

{

MessageBeep (0) ;

return 0 ;

}

iStatus = STATUS_WORKING ;

params.hwnd = hwnd ;

params.bContinue = TRUE ;

_beginthread (Thread, 0, &params) ;

InvalidateRect (hwnd, NULL, TRUE) ;

return 0 ;

case WM_RBUTTONDOWN:

params.bContinue = FALSE ;

return 0 ;

case WM_CALC_DONE:

lTime = lParam ;

iStatus = STATUS_DONE ;

InvalidateRect (hwnd, NULL, TRUE) ;

return 0 ;

case WM_CALC_ABORTED:

iStatus = STATUS_READY ;

InvalidateRect (hwnd, NULL, TRUE) ;

return 0 ;

case WM_PAINT:

hdc = BeginPaint (hwnd, &ps) ;

GetClientRect (hwnd, &rect) ;

wsprintf (szBuffer, szMessage[iStatus], REP, lTime) ;

DrawText (hdc, szBuffer, -1, &rect,

DT_SINGLELINE | DT_CENTER | DT_VCENTER) ;

EndPaint (hwnd, &ps) ;

return 0 ;

case WM_DESTROY:

PostQuitMessage (0) ;

return 0 ;

}

return DefWindowProc (hwnd, message, wParam, lParam) ;

}

你可能感兴趣的:(volatile)