系统级编程Lab 14. Exception and Process/Thread

来源:互联网 发布:中国出口构成 知乎 编辑:程序博客网 时间:2024/05/18 17:44

系统级编程最后一周的实验,一共5个Practice,因为网上没有相关的解答,我给出自己的解答,有兴趣的可以参考参考,有误的可以发送我的邮箱doglikejie@163.com交流



这是ppt的题目要求

我分析之后给出我的源代码

Practice1

第一题是在鼠标点击位置显示时间

我使用了以下重要函数来实现这一功能

GetLocalTime(),这个函数的使用,我先定义了一个SYSTEMTIME类型的变量systime,然后GetLocalTime(&systime);这一行代码把本地时间储存在systime变量里。

然后很重要的一个函数wsprintf(),为什么我这里使用wsprintf函数而不是老师给的sprintf函数,因为我在vs2017环境下编译意外的发现sprintf函数无法被识别,具体原因我也不知道,所以就用了wsprintf函数代替。

 wsprintf(str, "[%d年%d月%d日%d时%d分%d秒]   ",

 systime.wYear, systime.wMonth, systime.wDay,

 systime.wHour, systime.wMinute, systime.wSecond);

因为windows编程没有printf这种函数,所以我用wsprintf函数的目的是为了将时间保存为字符串便于打印。我们利用systime.wYear等进一步确定精确的年月日时分秒。

 x = LOWORD(lParam);

 y = HIWORD(lParam);

这两行分别保存横坐标和纵坐标,关于如何保存鼠标的问题,我查阅网上发现不同的解法,我这里偷懒直接int两个变量x,y保存,网上的通解应该是POINT 一个变量,然后通过变量.x,变量.来储存横纵坐标,这两种方法的优劣我还没思考过。

 hdc = GetDC(hwnd);

 //输出字符串

 TextOut(hdc, x, y, str, strlen(str));

ReleaseDC(hwnd, hdc);

GetDC()和ReleaseDC()必须成对出现,GetDC之后必须释放掉。TextOut负责打印字符串,参数的用法可以查阅msdn。

#include <windows.h>

 

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

 

int WINAPI WinMain (HINSTANCE hInstance,HINSTANCE hPrevInstance,

                    PSTR szCmdLine,int iCmdShow)

{

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

     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,                  // window class name

                          TEXT ("The Hello Program"),// window caption

                          WS_OVERLAPPEDWINDOW,        // window style

                          CW_USEDEFAULT,              // initial x position

                          CW_USEDEFAULT,              // initial y position

                          CW_USEDEFAULT,              // initial x size

                          CW_USEDEFAULT,              // initial y size

                          NULL,                       // parent window handle

                          NULL,                       // window menu handle

                          hInstance,                  // program instance handle

                          NULL) ;                     // creation parameters

     

     ShowWindow (hwnd, iCmdShow) ;

     UpdateWindow (hwnd) ;

     

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

     {

          TranslateMessage (&msg) ;

          DispatchMessage (&msg) ;

     }

     return msg.wParam ;

}

 

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

{

     HDC         hdc ;

     PAINTSTRUCT ps ;

     RECT        rect ;

 int         x, y;//分别储存横纵坐标

 CHAR        str[100];//储存转换成字符串的时间

 SYSTEMTIME systime;//负责储存系统时间

     

     switch (message)

     {

     case WM_CREATE:

          //PlaySound (TEXT ("hellowin.wav"), NULL, SND_FILENAME | SND_ASYNC) ;

          return 0 ;

 

 case WM_LBUTTONDOWN:

 x = LOWORD(lParam);

 y = HIWORD(lParam);

 GetLocalTime(&systime);

 wsprintf(str, "[%d年%d月%d日%d时%d分%d秒]   ",

 systime.wYear, systime.wMonth, systime.wDay,

 systime.wHour, systime.wMinute, systime.wSecond);

 hdc = GetDC(hwnd);

 //输出字符串

 TextOut(hdc, x, y, str, strlen(str));

 ReleaseDC(hwnd, hdc);

 break;

 return 0;

 

     case WM_PAINT:

          hdc = BeginPaint (hwnd, &ps) ;

          

          GetClientRect (hwnd, &rect) ;

          

          DrawText (hdc, TEXT ("Hello, world"), -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) ;

}

 

上面是我修改后的源代码

 

截图明显看出已经正确的实现了功能。当然我也思考过如何打印一次时间把上一次的使时间消除掉。因为老师没有要求,所以我也没有花时间实现这个功能了。感兴趣的可以自己尝试尝试。

Practice2 Add thread to DrawRect

Add thread to solve the problem in the program

题目源代码运行后,主要问题是,当我们左击鼠标一切正常,然而我们右击鼠标时,程序会进入一个无限画画的死循环,题目要求的是添加线程以解决问题。现在给出分析和源代码。

这里我用的是CreateThread()函数来建立新线程,下面是CreateThread()函数的定义,我们接下来将根据这个定义建立线程。

HANDLE CreateThread(    

  LPSECURITY_ATTRIBUTES lpThreadAttributes, // 安全属性,一般为NULL  

  DWORD dwStackSize,                        // 初始的栈大小,给NULL即可(系统会设置默认值)  

  LPTHREAD_START_ROUTINE lpStartAddress,    // 线程函数地址  

  LPVOID lpParameter,                       // 线程参数,传递给线程函数的参数  

  DWORD dwCreationFlags,                    // 创建的操作,如挂起等操作,为NULL则立即运行  

  LPDWORD lpThreadId                        // 线程的ID,一般不需要,给NULL  

);  

同时我们将while(1)那整个循环放入到线程函数中

DWORD WINAPI printThread(LPVOID lpParameter)

{

HBRUSH hBrush;

HDC    hdc;

int    xLeft, xRight, yTop, yBottom, iRed, iGreen, iBlue;

while (1)

{

if (cxClient != 0 || cyClient != 0)

{

xLeft = rand() % cxClient;

xRight = rand() % cxClient;

yTop = rand() % cyClient;

yBottom = rand() % cyClient;

iRed = rand() & 255;

iGreen = rand() & 255;

iBlue = rand() & 255;

 

hdc = GetDC(hwnd);

hBrush = CreateSolidBrush(RGB(iRed, iGreen, iBlue));

SelectObject(hdc, hBrush);

 

Rectangle(hdc, min(xLeft, xRight), min(yTop, yBottom),

max(xLeft, xRight), max(yTop, yBottom));

 

ReleaseDC(hwnd, hdc);

DeleteObject(hBrush);

}

}

return 0;

}

接下来每点击右键一次,新建一个线程,然而那个线程并行运行,因此并不影响我们“看到”的线程的操作。


现在是左键情况,我们现在点击右键观察


 这里注意右边诊断绘画里进行内存的变化,很明显看出进行内存使用变多,意思也就是那些线程被成功创建了!

#include <windows.h>

#include <process.h>

 

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

 

HWND hwnd ;

int  cxClient, cyClient ;

 

int WINAPI WinMain (HINSTANCE hInstance,HINSTANCE hPrevInstance,

                    PSTR szCmdLine,int iCmdShow)

{

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

     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 ("Random Rectangles"),

                          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 ;

}

 

DWORD WINAPI printThread(LPVOID lpParameter)

{

HBRUSH hBrush;

HDC    hdc;

int    xLeft, xRight, yTop, yBottom, iRed, iGreen, iBlue;

while (1)

{

if (cxClient != 0 || cyClient != 0)

{

xLeft = rand() % cxClient;

xRight = rand() % cxClient;

yTop = rand() % cyClient;

yBottom = rand() % cyClient;

iRed = rand() & 255;

iGreen = rand() & 255;

iBlue = rand() & 255;

 

hdc = GetDC(hwnd);

hBrush = CreateSolidBrush(RGB(iRed, iGreen, iBlue));

SelectObject(hdc, hBrush);

 

Rectangle(hdc, min(xLeft, xRight), min(yTop, yBottom),

max(xLeft, xRight), max(yTop, yBottom));

 

ReleaseDC(hwnd, hdc);

DeleteObject(hBrush);

}

}

return 0;

}

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

{

 

 

     switch (message)

     {

     case WM_CREATE:

          return 0;

     case WM_RBUTTONDOWN:

 HANDLE hThread = CreateThread(0, 0, printThread, (LPVOID)10,CREATE_SUSPENDED, 0);

 return 0 ;

 case WM_LBUTTONDOWN:

 MessageBox(hwnd,"Left button down!","点击左键",MB_OK);

 return 0;

     case WM_SIZE:

          cxClient = LOWORD (lParam) ;

          cyClient = HIWORD (lParam) ;

          return 0 ;

          

     case WM_DESTROY:

          PostQuitMessage (0) ;

          return 0 ;

     }

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

}

这是源代码

注意在vs下编译

 HANDLE hThread = CreateThread(0, 0, printThread, (LPVOID)10, CREATE_SUSPENDED, 0);会报错,但是却不影响使用,所以我也没深究了。

 

P3

新建两个线程然后让他们在主函数里运行之后用WaitForMultipleObjects函数等待线程结束,P3是SSD6 Exercise6的原题,我在这里也就直接给出简单分析和标准答案了。

/*

ThreadedClient.cpp

 

A threaded database client.

 */

 

#include <iostream>

 

#include "servers.h"

 

#ifdef _MSC_VER

#include <windows.h>

#include <winbase.h>

#include <process.h>

typedef __int64 INT64_T;

typedef unsigned __int64 UINT64_T;

 

typedef LONGLONG time_ms_t;

 

time_ms_t getTimeInMilliseconds() {

SYSTEMTIME stime;

GetSystemTime( &stime );

 

FILETIME ftime;

LARGE_INTEGER time;

 

SystemTimeToFileTime( &stime, &ftime ); /* if this fails... */

 

time.HighPart = ftime.dwHighDateTime;

time.LowPart = ftime.dwLowDateTime;

 

/* FileTime is in 100ns intervals since 1/1/1601 */

return time.QuadPart / 10000;

}

#endif

 

/*

ostream &operator <<( ostream &out, string *str ) {

 

Send a string to an output stream.

 */

ostream &operator<<(ostream &out,string *str) {

if (str)

return out << str->data();

else

return out;

}

 

/*

    ostream & operator<< ( ostream &out, INT64_T num )

 

Print a 64-bit unsigned integer to the given output stream.

  */

ostream &operator<<(ostream &out,INT64_T snum ) {

#define _OSTR_LL_LEN 21

if (snum) {

char buffer[_OSTR_LL_LEN];

int i = _OSTR_LL_LEN - 1;

        UINT64_T num;

if (snum < 0) num = -snum;else num =snum;

 

buffer[i] = '\0';

while (num) {

buffer[--i] = ('0' + (int) (num % 10));

num /= 10;

}

if (snum < 0) buffer[--i] ='-';

return out << buffer + i;

}else return out << '0';

}

 

/*

  These are the two thread routines, each of which will run as

  as a separate thread

*/

 

Personal *global_personal = NULL;

void __cdecl personal_thread(void *arg ) {

int acct = *( (int *)arg );

global_personal = GetPersonalInformation( acct );

}

 

AccountInfo *global_account = NULL;

void __cdecl account_thread(void *arg ) {

int acct = *( (int *)arg );

global_account = GetAccountInformation( acct );

}

 

/*

int main( int argc, char *argv[]

 

You should modify this function to use threads.

 */

int main( int argc, char *argv[] ) {

  HANDLE handles[2];

  if (argc != 2) {

    cerr << "usage: " << argv[0]<< " [account_number]" << endl;

    exit(1);

  }

  int account = atoi( argv[1] );

  

  time_ms_t start = getTimeInMilliseconds();

  cout << "Retrieving...";

  cout.flush();

  

  handles[0] = (HANDLE) _beginthread( personal_thread, 0, &account );

  if (handles[0] == (HANDLE) -1L) {

    cout << "Couldn't create thread!" << endl;

    exit(1);

  }

  

  handles[1] = (HANDLE) _beginthread( account_thread, 0, &account );

  if (handles[1] == (HANDLE) -1L) {

    cout << "Couldn't create thread!" << endl;

    exit(1);

  }

  

  WaitForMultipleObjects( 2, handles, TRUE,INFINITE );

  cout << "done" << endl;

  

  time_ms_t end = getTimeInMilliseconds();

  cout << "done (" << end - start <<"ms)" << endl;

  

  if (global_personal) {

    cout << account << ": " << global_personal->FirstName<< " "

 << global_personal->LastName << endl;

    cout << global_personal->Address<< endl;

    cout << "Balance: " << global_account->Balance<<  ", " 

 << global_account->Pending

 << " pending, " << global_account->Share<< " share" << endl;

    

  }

  delete global_personal;

  delete global_account;

 

  return 0;

}

P4

程序问题

 

打印出的count的值随机,

现象名称:(终止)异常

发生原因:_sleep()函数提前终止了线程运行,将_sleep()函数删去,发现运行结果正常为0

#include <stdio.h>

#include <process.h>

#include <windows.h>

 

 

int count=0;

 

void thread1(void*pvoid)

{

while(count<1000000000)

{

       count++;

}

}

 

void thread2(void*pvoid)

{

while(count>-1000000000)

{

       count--;

}

}

 

int main()

{

_beginthread(thread1,0,NULL);

_beginthread(thread2,0,NULL);

 

//_sleep(100);

printf("%d\n",count);

getchar();

return 0;

}


P5单选题,SSD6有现成的答案,我写这篇博客的原因是因为之前的lab'中参阅了不少前辈们的答案,在做lab14发现暂无答案,希望自己的思路能帮助到后面的同学。


阅读全文
'); })();
0 0
原创粉丝点击
热门IT博客
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 乔山跑步机t2101 乔山跑步机旗舰店 乔山公墓价格 乔山跑步机专卖店 乔山t101跑步机 乔山跑步机售后服务 乔山t941价格 乔山跑步机 t941 乔山跑步机 t931 乔山跑步机 8.0t 乔山跑步机 t921 乔山跑步机t942 乔山跑步机t931 乔山商用健身器材 乔山6.0t跑步机 乔山跑步机保修几年 乔山二手跑步机 乔山健身器材 二手乔山跑步机 乔峰 乔峰扮演者 梁家仁乔峰 张无忌 乔峰 仙葫 乔峰 乔峰图片 萧峰乔峰 洪七公提到乔峰 乔峰干王语嫣 天龙之乔峰九转玄功 乔峰在马上肉阿紫 乔峰在桥边看到一个黑衣汉子 天龙之乔峰纵横天下 乔峰大战康敏 乔峰和洪七公 乔峰大战聚贤庄 王语嫣评价乔峰的武功 乔峰的擒龙功的来历 乔峰和段誉在何处义结金兰 乔峰出场bgm叫什么 乔峰对鸠摩智 第一个告知乔峰姓萧的是谁