zoukankan      html  css  js  c++  java
  • 多线程中的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) ;
    
    }
    
  • 相关阅读:
    SQLServer 使用ADSI执行分布式查询ActiveDorectory对象
    GridView的DataFormatString
    我的第一篇博客
    delphi for php 帮助文档的笔记(二)
    用delphiforphp来编写算法注册机第一节
    delphiforphp的中文环境的搭建
    初步拟定的delphiforphp的学习计划
    取當前日期各种數据庫的寫法(转存,备查)
    php两页间传变量(转发,备查)
    关于delphiforphp我想说的。
  • 原文地址:https://www.cnblogs.com/qinfengxiaoyue/p/2890564.html
Copyright © 2011-2022 走看看