必威体育Betway必威体育官网
当前位置:首页 > IT技术

window编程之CreateThread

时间:2019-09-26 20:12:11来源:IT技术作者:seo实验室小编阅读:70次「手机版」
 

createthread

采用CreateThread()创建多线程程序

在window环境下,Win32 提供了一系列的API函数来完成线程的创建、挂起、恢复、终结以及通信等工作

1、主要的函数列表:

序号

函数名

功能

1

CreateThread()

创建一个新线程

2

ExitThread()

正常结束一个线程的执行

3

TerminateThead()

强制终止一个线程的执行

4

ResumeThread()

重启一个线程

5

suspendthread()

挂起一个线程

6

GetExiCodeThread()

得到一个线程的退出码

7

GetThreadpriority()

得到一个线程的优先级

8

SetThreadPriority()

设置一个线程的优先级

9

Closehandle()

关闭一个线程的句柄

10

CreateRemoteThread()

再另一个进程中创建一个新线程

11

PostThreadmessage()

发送一条消息给指定的线程

12

GetCurrentThread()

得到当前的线程句柄

13

GetCurrentThreadId()

得到当前线程的ID

14

GetThreadId()

得到指定线程的ID

15

WaitForSingleObject()

等待单个对象

16

waitforMultipleObjects()

等待多个对象

关于多线程的API函数还有很多,以上只是列出了一些比较常用的函数,欲知更多函数和函数的使用方法,请参考MSDN或网络资源,在此就不再介绍了

2、线程函数的定义:

线程函数的规范格式定义为

Dword  WINAPI ThreadProc (LPVOID lpParam);//格式不正确将无法调用成功。函数名称没有限制,只要符合命名规则就可以。

但我常常看到有下列的线程函数定义:

void ThreadProc ();//该格式也是可以的,但使用的时候要这样通过

LPTHREAD_START_ROUTINE转换,如:

(LPTHREAD_START_ROUTINE)ThreadProc

我建议还是使用规范的格式比较好,不推荐使用void ThreadProc ()格式。不信就请看看MSDN的说明吧:

Do not declare this callback function with a void return typeand cast the function pointer to LPTHREAD_START_ROUTINE when creatingthe thread. Code that does this is common, but it can crash on 64-bit windows.

而且线程函数必须是全局函数,不能在类中声明和定义

3、多线程实例1:

我在此将写一个简单的多线程程序,用以展示多线程的功能和使用方法。该程序的主要的思想是画3个进度条,分别以多线程和单线程方式完成,大家可以比较一下。

说明:

(1)该程序还将和单线程做对比。

(2)由于给线程的函数传递了多个参数,所以采用结构体的方式传递参数。

(3)为了演示效果,采用了比较耗时的打点处理。

主要的函数如下:

在头文件的定义

[cpp] view plain copy  print?

  1. //线程函数声明  
  2. dword WINAPI ThreadProc(LPVOIDlpParam);  
  3. //为了传递多个参数,我采用结构体  
  4. struct threadInfo  
  5. {  
  6.     HWND hWnd;       //窗口句柄  
  7.     int  noffset;    //偏移量  
  8.     colorref clrRGB; //颜色  
  9. };  
  10.    
  11. protected:  
  12. HANDLE hThead[3];    //用于存储线程句柄  
  13.     DWORD  dwThreadID[3];//用于存储线程的ID  
  14.   threadInfo Info[3];   //传递给线程处理函数的参数  

//实现文件中

[cpp] view plain copy  print?

  1. //单线程测试  
  2. void CMultiThread_1Dlg::OnBnClickedButton1()  
  3. {  
  4.     // TODO: 在此添加控件通知处理程序代码  
  5.     //使能按钮  
  6.     getdlgitem(IDC_BUTTON1)->EnableWindow(FALSE);  
  7.     GetDlgItem(IDC_BUTTON2)->EnableWindow(FALSE);  
  8.     CDC *dc = GetDC();  
  9.     CRect rt;  
  10.     GetClientRect(rt);  
  11.     dc->FillSolidRect(0,0,rt.Width(),rt.Height()-70,RGB(240,240,240));//刷新背景  
  12.     dc->textout(97,470,"#1");  
  13.     dc->TextOut(297,470,"#2");  
  14.     dc->TextOut(497,470,"#3");  
  15.     //#1  
  16.     for (int i=0;i<460;i++)  
  17.     {  
  18.        for (int j =10 ;j<200;j++)  
  19.        {  
  20.            dc->SetPixel(j,460-i,RGB(255,0,0));  
  21.        }  
  22.     }  
  23.     //#2  
  24.     for (int i=0;i<460;i++)  
  25.     {  
  26.        for (int j =210 ;j<400;j++)  
  27.         {  
  28.            dc->SetPixel(j,460-i,RGB(0,255,0));  
  29.        }  
  30.     }  
  31.     //#3  
  32.     for (int i=0;i<460;i++)  
  33.     {  
  34.        for (int j =410 ;j<600;j++)  
  35.        {  
  36.            dc->SetPixel(j,460-i,RGB(0,0,255));  
  37.        }  
  38.     }  
  39.     ReleaseDC(dc);  
  40.     //使能按钮  
  41.     GetDlgItem(IDC_BUTTON1)->EnableWindow(TRUE);  
  42.     GetDlgItem(IDC_BUTTON2)->EnableWindow(TRUE);  
  43. }  
  44.    
  45. //多线程测试  
  46. void CMultiThread_1Dlg::OnBnClickedButton2()  
  47. {  
  48.     // TODO: 在此添加控件通知处理程序代码  
  49.     CDC *dc = GetDC();  
  50.     CRect rt;  
  51.     GetClientRect(rt);  
  52.     dc->FillSolidRect(0,0,rt.Width(),rt.Height()-70,RGB(240,240,240));//刷新背景  
  53.     dc->TextOut(97,470,"#1");  
  54.     dc->TextOut(297,470,"#2");  
  55.     dc->TextOut(497,470,"#3");  
  56.     //初始化线程的参数  
  57.     Info[0].hWnd = Info[1].hWnd = Info[2].hWnd = GetSafeHwnd();  
  58.     Info[0].nOffset = 10;Info[1].nOffset = 210;Info[2].nOffset = 410;  
  59.     Info[0].clrRGB = RGB(255,0,0);Info[1].clrRGB= RGB(0,255,0);Info[2].clrRGB = RGB(0,0,255);  
  60.     //创建线程  
  61.     for (int i = 0;i<3;i++)  
  62.     {  
  63.        hThead[i] = CreateThread(NULL,0,ThreadProc,&Info[i],0,&dwThreadID[i]);  
  64.     }  
  65.     ReleaseDC(dc);  
  66. }  
  67.    
  68. DWORD WINAPI ThreadProc(LPVOIDlpParam)  
  69. {  
  70.     threadInfo*Info = (threadInfo*)lpParam;  
  71.     CDC *dc = CWnd::FromHandle(Info->hWnd)->GetDC();  
  72.     for (int i=0;i<460;i++)  
  73.     {  
  74.        for (int j=Info->nOffset;j<Info->nOffset+190;j++)  
  75.        {  
  76.            dc->SetPixel(j,460-i,Info->clrRGB);  
  77.        }  
  78.     }  
  79.     DeleteObject(dc);  
  80.     return 0;  
  81. }  

运行效果:

单线程测试

多线程测试

工程源码下载地址:

http://download.csdn.net/detail/cbnotes/4857152

欢迎大家修改和指正。

注意事项:

(1)传递给线程执行函数的参数不能是局部变量,而且必须是参数的地址。如:

Int nOffset = 10;

CreateThread(NULL,0,ThreadProc,nOffset,0,&dwThreadID[i]);//错误

CreateThread(NULL,0,ThreadProc,&nOffset,0,&dwThreadID[i]);//错误

Int *pOffset = newint(10);

CreateThread(NULL,0,ThreadProc,pOffset,0,&dwThreadID[i]);//正确

(2)线程执行函数必须是全局函数。

(3)请大家改改下面的程序,且解释下为什么?

这是我开始写程序遇到的一个问题,

改写上面的函数:只是将结构体中一个参数改为CDC指针,以便直接调用。

struct threadInfo

{

CDC * dc;        //画布

int  nOffset;    //偏移量

COLORREF clrRGB; //颜色

};

//多线程测试

void CMultiThread_1Dlg::OnBnClickedButton2()

{

// TODO: 在此添加控件通知处理程序代码

CDC *dc = GetDC();

CRect rt;

GetClientRect(rt);

dc->FillSolidRect(0,0,rt.Width(),rt.Height()-70,RGB(240,240,240));//刷新背景

dc->TextOut(97,470,"#1");

dc->TextOut(297,470,"#2");

dc->TextOut(497,470,"#3");

//初始化线程的参数

Info[0].dc = Info[1]dc = Info[2].dc = dc;

Info[0].nOffset = 10;Info[1].nOffset = 210;Info[2].nOffset = 410;

Info[0].clrRGB = RGB(255,0,0);Info[1].clrRGB= RGB(0,255,0);Info[2].clrRGB = RGB(0,0,255);

//创建线程

for (int i = 0;i<3;i++)

   {

  hThead[i] = CreateThread(NULL,0,ThreadProc,&Info[i],0,&dwThreadID[i]);

   }

   //ReleaseDC(dc);

}

//线程执行函数

DWORD WINAPI ThreadProc(LPVOIDlpParam)

{

threadInfo*Info = (threadInfo*)lpParam;

for (int i=0;i<460;i++)

   {

  for (int j=Info->nOffset;j<Info->nOffset+190;j++)

  {

  Info->dc->SetPixel(j,460-i,Info->clrRGB);

  }

   }

return 0;

}

运行结果:

为什么会这样呢?我还没有找到答案,望大家能给我个解释,谢谢。

==========================================================

4、多线程实例2:

该实例将演示一个简单的多线程协同工作的例子,以供大家学习和参考。大致原理是:5个人开始比赛(比如赛跑),谁先完成比赛就结束,并统比赛时间和赢者。主线程用于界面的相关显示,5个线程模拟5个人的行为(赛跑),另外一个线程用于检测5个线程的运行情况,只要有人到达终点,比赛就结束并做相关的技术统计。

主要函数为:

MulitThread_2Dlg.h : 头文件

//声明线程处理函数

DWORD WINAPI ThreadProc1(LPVOIDlpParam);

DWORD WINAPI ThreadProc2(LPVOIDlpParam);

//为了传递多个参数,我采用结构体

struct threadInfo1

{

HWND hWnd;       //窗口句柄

int  nOffset;    //偏移量

};

struct threadInfo2

{

HWND hWnd;          //窗口句柄

HANDLE *phHandle;   //偏移量

};

protected:

long   m_nTime;//时间

HANDLE m_hThead[5];    //用于存储线程句柄

HANDLE hThead;     //用于存储线程句柄

DWORD  m_dwThreadID[5];//用于存储线程的ID

threadInfo1Info1[5];  //传递给线程处理函数的参数

threadInfo2Info2;

// MulitThread_2Dlg.cpp : 实现文件

//更新时间:毫秒

void CMulitThread_2Dlg::OnTimer(UINT_PTRnIDEvent)

{

// TODO: 在此添加消息处理程序代码和/或调用默认值

m_nTime+=100;//毫秒为单位

CString str;

str.Format("时间:%.1f秒",m_nTime/1000.0);

GetDlgItem(IDC_STATIC2)->SetWindowText(str);

CDialog::OnTimer(nIDEvent);

}

//消息处理函数

LRESULT CMulitThread_2Dlg::OnGameOver(WPARAMwParam, LPARAMlParam)

{

KillTimer(1);//关闭计时器

if (wParam ==0)

   {//出错

  GetDlgItem(IDC_STATIC1)->SetWindowText("出错啦!");

  GetDlgItem(IDC_STATIC2)->SetWindowText("---");

  AfxMessageBox("出错啦!",MB_OK|MB_ICONERROR);

   }

else

   {//成功

  //显示结果

  char *pName[] = {"张三","李四","王二","小蔡","赵干"};

  CStringstr;

  str.Format("赢者:%s",pName[lParam]);

  GetDlgItem(IDC_STATIC1)->SetWindowText(str);

   }

//使能开始按钮,以便可以开始下一次比赛

GetDlgItem(IDC_BUTTON1)->EnableWindow(TRUE);

return 0;

}

//开始比赛

void CMulitThread_2Dlg::OnBnClickedButton1()

{

// TODO: 在此添加控件通知处理程序代码

//使能开始按钮:无效

GetDlgItem(IDC_BUTTON1)->EnableWindow(FALSE);

m_nTime =0;//初始化时间为

CDC *dc = GetDC();

CRect rt;

GetClientRect(rt);

dc->FillSolidRect(40,0,rt.Width()-49,rt.Height()-50,RGB(240,240,240));//刷新背景

ReleaseDC(dc);

//初始化线程的参数

Info1[0].hWnd = Info1[1].hWnd = Info1[2].hWnd = Info1[3].hWnd = Info1[4].hWnd = GetSafeHwnd();

Info1[0].nOffset = 0;Info1[1].nOffset = 90;Info1[2].nOffset = 180;Info1[3].nOffset = 270;Info1[4].nOffset = 360;

//创建线程

for (int i = 0;i<5;i++)

   {  

  m_hThead[i] = CreateThread(NULL,0,ThreadProc1,&Info1[i],CREATE_SUSPENDED,&m_dwThreadID[i]);   

   }

SetTimer(1,100,NULL);//开始计时

GetDlgItem(IDC_STATIC1)->SetWindowText("进行中...");

//开始运行

for (int i = 0;i<5;i++)

   {  

  ResumeThread(m_hThead[i]); 

   }

//开始运行监测结果线程

Info2.hWnd = m_hWnd;

Info2.phHandle = m_hThead;

hThead = CreateThread(NULL,0,ThreadProc2,&Info2,0,NULL);

}

//比赛线程

DWORD WINAPI ThreadProc1(LPVOIDlpParam)

{

threadInfo1*info = (threadInfo1*)lpParam;

CDC *dc = CWnd::FromHandle(info->hWnd)->GetDC();

for (int i=40;i<570;i+=2)

   {

  for (int j=0;j<1000;j++)

  {//重复操作,以便人眼观察

  dc->Rectangle(CRect(i,info->nOffset,i+1,info->nOffset+80));

  }

   }

DeleteObject(dc);

return 0;

}

//监视线程:谁先完成比赛就结束

DWORD WINAPI ThreadProc2(LPVOIDlpParam)

{

threadInfo2*info = (threadInfo2*)lpParam;

DWORD dwRet = 0;

//等待个线程中的一个完成

dwRet = WaitForMultipleObjects(5,info->phHandle,FALSE,INFINITE);

if (dwRet == WAIT_failed)

   {//出错啦

  ::SendMessage(info->hWnd,WM_GAMEOVER,0,0);

  return 0;

   }

//终止各个线程

for (int i=0;i<5;i++)

   {

  terminatethread(info->phHandle[i],0);

   }

//发送比赛结果消息

   ::SendMessage(info->hWnd,WM_GAMEOVER,1,dwRet- WAIT_OBJECT_0);

return 0;

}

运行结果:

工程源码

http://download.csdn.net/detail/u013896064/9906124

欢迎大家修改和指正。

注意事项:

1.    该程序连主线程一共7个线程。其中一个线程专门用于检测5个比赛线程的运行结果检测,为什么要专门开这个线程而不在主线程中进行呢?主要是WaitForMultipleObjects()函数是一个阻塞函数,如果在主线程中运行该函数,将使整个程序的界面不能操作(如:不能移动窗口等),因为一直阻塞在WaitForMultipleObjects函数处,而不能处理其它消息,不信大家可以试试。

2.    线程同步的两个比较重要的函数为WaitForSingleObject()和WaitForMultipleObjects(),具体使用请参考MSDN。这两个函数都是阻塞函数,一直等待授信的对象发生才返回。

3.    采用消息的方式通知主线程的运行结果,该方法比较简单有效。一般的多线程程序都是采用主线程负责显示,辅助线程来完成比较耗时的任务,等任务完成后再通知主线程运行结果。

相关阅读

2019Windows7 虚拟机安装系统图文教程

随着网络的发展,虚拟机越来越显得重要,常见的虚拟机有很多种,比如VMware,Vbox等,今天给大家带来VMware安装windows7教程。 准备工作 首

关于 contentWindow, contentDocument

没有永恒的技术只有变态的需求,没有好说的客户只有无奈的开发者, 如果iframe的出现是一个错误的话,iframe里边在来一个iframe那是错

windows事件查看器

打开方式:右键左下角的windows ,然后按v                         或者 Windows+R 后 输入eventvwr.msc 也行 主要

使用wget (wget for windows)

一、什么是wget GNU Wget是一个在网络上进行下载的简单而强大的自由软件,其本身也是GNU计划的一部分。它的名字是“World Wide We

062_Windows的盘符修改

一个电脑重新安装后发现盘符不连续,一个C一个G,看上去感觉有点不舒服。感觉还是一个C一个D看着习惯。 尝试了一下,修改起来原来还比

分享到:

栏目导航

推荐阅读

热门阅读