关于Win32 API(VC作为程序设计语言)的创建线程,解决互斥访问临界资源问题

来源:互联网 发布:ubuntu编辑只读文件 编辑:程序博客网 时间:2024/05/16 07:10

此工程在4月份被更改,下面的是初级试验阶段的产物。不过能够进行一些交流。

 

2010-03-19 23:46:39

 

首先是工程(名为supper),在VC++6.0下是Windows Application,dsw文件的写法:

 

Microsoft Developer Studio Workspace File, Format Version 6.00
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!

###############################################################################

Project: "supper"="./supper.dsp" - Package Owner=<4>

Package=<5>
{{{
}}}

Package=<4>
{{{
}}}

###############################################################################

Global:

Package=<5>
{{{
}}}

Package=<3>
{{{
}}}

###############################################################################

 

随后是头文件:

 

/************************************
*   文 件 信 息    *
*    File Infomation   *
*         *
*文件名称  : supper.h  *
*File Name  : supper.h  *
*文件作者  : Woody.c   *
*File Athour : Woody.c   *
*文件最初版本 : 1.1版   *
*Create Edition : version 1.1  *
*文件创建时间 : 2010年3月19日 *
*Create Date : 2010年3月19日 *
*当前版本  : 1.1版   *
*Current Editon : version 1.1  *
*最后一次修改 : 2010年3月19日 *
*Last Modify : 2010年3月19日 *
*         *
*************************************/

#ifndef ___SUPPER___H___
#define ___SUPPER___H___

//加载支持:
#include <windows.h>
#include <time.h>
#include <process.h>

//宏定义:
//版本
#define EDITION   "Supper v1.1"
#define MAXTHINKER  5    //思考者人数

 


//Sub声明:
//主入口函数WinMain()
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,PSTR szCmdLine, int iCmdShow);
//消息处理函数WndProc()
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
//动作线程
VOID Thread(PVOID pvoid);
//筷子校验线程(可屏蔽)
VOID TestChop(PVOID pvoid);
//吃动作
void Eat(HDC hdc, int id, char * szName);
//思考动作
void Think(HDC hdc, int id, char * szName);

//示例函数Example()
//void Example(void);

 

//全局变量:
HWND hwnd;
int  cxClient, cyClient;
int  GnChops[MAXTHINKER] = {1, 1, 1, 1, 1};          //筷子的信息量
char GszName[5][20] = {"Einstein", "Plato", "Marx", "Confusious", "Galie"};  //姓名
static int nID;

#endif

 

随后是源文件,小工程单文件搞定:

/************************************
*   文 件 信 息    *
*    File Infomation   *
*         *
*文件名称  : supper.c  *
*File Name  : supper.c  *
*文件作者  : Woody.c   *
*File Athour : Woody.c   *
*文件最初版本 : 1.1版   *
*Create Edition : version 1.1  *
*文件创建时间 : 2010年3月19日 *
*Create Date : 2010年3月19日 *
*当前版本  : 1.1版   *
*Current Editon : version 1.1  *
*最后一次修改 : 2010年3月19日 *
*Last Modify : 2010年3月19日 *
*         *
*************************************/
#include "supper.h"

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
 static TCHAR szAppName[] = TEXT(EDITION);    
 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;   //TEXT("IDR_MENU_EXAMPLE");
 wndclass.lpszClassName = szAppName;
 
 if(!RegisterClass(&wndclass))
 {
  MessageBox (NULL, TEXT("This program requires Windows NT!"),szAppName, MB_ICONERROR);
  return 0;
 }

 hwnd = CreateWindow(szAppName, TEXT(EDITION), WS_POPUP,
  100, 100, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
 
 ShowWindow (hwnd,SW_SHOWMAXIMIZED);
 UpdateWindow(hwnd);
 
 srand((unsigned)time(NULL));

 while(GetMessage(&msg, NULL, 0, 0))
 {
  TranslateMessage(&msg);
  DispatchMessage(&msg);
 }  
 
 return msg.wParam ;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
 PAINTSTRUCT    ps;       //绘图结构体 
 HDC      hdc;      //设备句柄handle of device
 HDC      hdcMem;      //同上
 static HINSTANCE  hInstance;     //静态HINSTANCE,表示当前实例。
// HFONT hfont;

 switch(message)
 {
 //窗口的创建:
 case WM_CREATE:  
  hInstance = ((LPCREATESTRUCT)lParam) -> hInstance;      //由传入消息的参数得到当前实例
  
  //开始线程
  _beginthread(Thread, 0, NULL);
  _beginthread(Thread, 0, NULL);
  _beginthread(Thread, 0, NULL);
  _beginthread(Thread, 0, NULL);
  _beginthread(Thread, 0, NULL);
  _beginthread(TestChop, 0, NULL);
    
  return 0 ;

 case WM_SIZE:
  cxClient = LOWORD(lParam) ;
  cyClient = HIWORD(lParam) ;
  return 0 ;

 case WM_KEYDOWN: 
  switch(wParam)
  {
  case VK_ESCAPE:   
        case VK_SPACE:
   PostQuitMessage (0) ;
   break;
  default:
   break;
  } 
  return 0;

 case WM_LBUTTONDOWN:
 case WM_RBUTTONDOWN:
  PostQuitMessage (0) ;
  return 0;

 case WM_PAINT:
  //开始绘图  
  cxClient = LOWORD(lParam);
  cyClient = HIWORD(lParam);
  hdc  = BeginPaint(hwnd, &ps);
  hdcMem = CreateCompatibleDC(hdc);       //创建一个与指定设备一致的内存设备描述表  
  
  DeleteDC(hdcMem);            //绘画动作结束,删除内存设备描述表
  EndPaint(hwnd, &ps);
       
  return 0 ;

     case WM_DESTROY:
   PostQuitMessage(0);
   return 0;
     }
     return DefWindowProc(hwnd, message, wParam, lParam);
}

VOID Thread(PVOID pvoid)
{
 static int nX   = 0;
 int   nID   = nX++; 
 HDC   hdc; 
 HFONT  hFont;

 hdc  = GetDC(hwnd);
 hFont = CreateFont(40, 40, 0, 0, 0, 0, 0, 0,
    GB2312_CHARSET, OUT_DEFAULT_PRECIS,
    CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
    DEFAULT_PITCH & FF_DONTCARE, "黑体");
 SelectObject(hdc, hFont);

 while(1)
 { 
  //对左右两方向筷子进行观察,如果都可得才拿起
  if(GnChops[nID] > 0 && GnChops[(nID + 1) % MAXTHINKER] > 0)
  {
   //加锁,即修改信息量,标志左右两筷子被占用
   GnChops[nID] = GnChops[nID] - 1;
   GnChops[(nID + 1) % MAXTHINKER] = GnChops[(nID + 1) % MAXTHINKER] - 1;
   SetTextColor(hdc, RGB(200,100,200));
   //执行吃动作(产生延迟)
   Eat(hdc, nID, GszName[nID]);
   //解锁,释放筷子的被占用状态
   GnChops[nID] = GnChops[nID] + 1;
   GnChops[(nID + 1) % MAXTHINKER] = GnChops[(nID + 1) % MAXTHINKER] + 1;
   //恢复思考,吃饱了,好好干!
   SetTextColor(hdc, RGB(100, 200, 200));
   Think(hdc, nID, GszName[nID]);
  }
  else//至少有一根筷子不可得
  {
   //继续思考
   SetTextColor(hdc, RGB(100, 200, 200));
   Think(hdc, nID, GszName[nID]);
  }
 }
 //释放开辟的字体
 DeleteObject(hFont);
 ReleaseDC(hwnd, hdc);
 _endthread();
}


VOID TestChop(PVOID pvoid)
{
 int i;
 HDC hdc;
 HBRUSH hBrush;

 hdc = GetDC(hwnd);

 while(1)
 {
  for(i = 0; i < MAXTHINKER; i++)
  {
   if(GnChops[i] > 0)
   {
    hBrush = GetStockObject(BLACK_BRUSH);
   }
   else
   {
    hBrush = GetStockObject(WHITE_BRUSH);
   }
   SelectObject(hdc, hBrush);
   Rectangle(hdc, i * 100 + 200, 150, i * 100 + 200 + 20, 170);
   DeleteObject(hBrush);   
  }
 }
 ReleaseDC(hwnd, hdc);
 _endthread();
}

void Eat(HDC hdc, int id, char * szName)
{
 int i;
 char szOutput[30];

 strcpy(szOutput, szName);
 strcat(szOutput, " is Eating !!!!  ");
 TextOut(hdc, 200, 200 + id * 50, szOutput, strlen(szOutput));

 i = rand()%1123 + 2131;
 Sleep(i);
}

void Think(HDC hdc, int id, char * szName)
{
 int i; 
 char szOutput[30];

 strcpy(szOutput, szName);
 strcat(szOutput, " is Thinking!  ");
 TextOut(hdc, 200, 200 + id * 50, szOutput, strlen(szOutput));
 
 i = rand()%1321 + 1231;
 Sleep(i);
}

注释比较少。这个完成的工作是解决“五个哲学家进餐问题”

 

自我记录:线程的创建,在process.h头文件下,据我所知有两种形式:

uintptr_t _beginthread(
   void( __cdecl *start_address )( void * ),   //目标函数指针
   unsigned stack_size,                                 //堆栈容量,若不需要则写0
   void *arglist                                               //传入目标函数的参数,void *类型,可以自己构造结构体
);
uintptr_t _beginthreadex(
   void *security,                                                              //形式,这个比较麻烦,参见MSDN解CreateThread()
   unsigned stack_size,                                                    //同样是堆栈容量
   unsigned ( __stdcall *start_address )( void * ),           //目标函数指针
   void *arglist,                                                                 //传入目标函数的参数
   unsigned initflag,                                                          //可为CREATE_SUSPENDED或0,前者进程被创建后默认为挂起
   unsigned *thrdaddr                                                      //进程ID的地址
);

一般我个人选用前者,参数少使用方便,但是切记在最后加“_endthread();”来完成对线程的释放,避免造成不必要的资源泄露问题。

第二个函数参数多,功能也相对强大,可以阻塞创建的线程1,而且也可以传出线程ID。

 

P.S:两个函数的返回值都是线程的句柄。