一 . 进度条从头走到尾
在资源视图中添加Process Control 和 Button
控件Process Control右键添加变量,Button双击添加函数如下:
做法一:
for(int i = 0; i <= 100; i++)//相对位置,所以要到=100 { m_proctrl.SetPos(i); }
做法二:
m_proctrl.SetStep(1);//SetStep与StepIt一起使用 int i = 0; while(i++ < 10) { m_proctrl.StepIt();//默认一次走10进度 }
二 . Windowsx消息响应机制
系统消息对列 -> 当前应用程序的消息对列 -> GetMessage()从对列中取出消息 -> TranslateMessage()翻译函数 -> DispatchMessage()分发函数 ->
Afxunclproc回调函数(所有的函数都有一个回调函数,即消息入口点函数)---消息发送到窗口----> pWnd -> windoproc ----消息映射表--------> 处理函数
tips:SendMessage()不进入程序的消息对列,但进入系统的消息对列
while(1) { proctrl.StepIt(); sleep(0);//没有效果,因为睡眠时没有其他消息要执行,没有取出消息 sleep(100);//进度条变缓慢 }
Sleep时,效果,可以执行其他消息吗 ? 进度条变慢:sleep(0);让出本次时间片,sleep(100):睡100s,醒来后再轮转到它才行 。 sleep时可以执行其他消息因为没有从消息对列中拿消息所以不能执行
下面的做法虽然可以在跑进度条的时候,接收其他消息,但二者不能同时执行,创建线程则可以。
while(1) { MSG msg; proctrl.StepIt(); //--------------可以并发处理别的消息------------ if(GetMessage(&msg,0,0,0))//从队列中取得消息 { TranslateMessage(&msg);//翻译消息 DispatchMessage(&msg);//分发消息 } //---------并发:轮换时间片,不能同时执行---------- }
三 . 创建线程
线程:进程中的执行单元 , 分配CPU的基本单位。
线程栈:存储在线程中创建的变量(线程退出,线程栈被销毁掉)
内核对象:计数器 (初始值为2,当为0时,释放内核对象)1.线程退出(-1)2.关闭句柄(-1)(CloseHandle()) ; openThread()计数器+1
挂起计数器 : SuspendThread()挂起计数器+1;ResumeThread()挂起计数器-1
信号:线程退出则有信号,否则无信号(WAIT_TIMEOUT)。
void CThreadtestDlg::OnBnClickedButton1() { //创建线程 if(!m_hThread)//线程不存在则创建线程 { m_bFlagQuit = true; m_hThread = CreateThread(NULL, //安全属性 0 ,//线程栈 默认1MB &ThreadProc, //函数地址 this, //线程参数 0 ,//创建标志 0 立即运行 CREATE_SUSPENDED 挂起 NULL //线程ID ); } else ResumeThread(m_hThread);//线程存在则恢复线程(挂起计数器-1),挂起计数器不能为负 }
线程执行的函数
DWORD WINAPI ThreadProc( LPVOID lpParameter)
//调用约定
//WINAPI (C++) stdcall 参数入栈顺序从右--左 函数本身清理
//WINAPIV (C) cdecl 参数入栈顺序从右--左 由调用者清理空间 支持可变的参数个数
{ CThreadtestDlg *pthis = (CThreadtestDlg *)lpParameter; while(pthis->m_bFlagQuit)//bool变量,退出时使用,不满足条件则线程退出 { pthis->m_proctrl.StepIt(); Sleep(100); } return 0; }
四 . 暂停按钮(挂起进程)
void CThreadtestDlg::OnBnClickedButton2() { SuspendThread (m_hThread);//挂起计数器+1 }
五 . 结束按钮(结束进程,关闭句柄)
void CThreadtestDlg::OnBnClickedButton3() { //1.正常退出 m_bFlagQuit = false; //2.强制退出 //ExitThread()退出调用它的线程 //判断线程是否已经退出,如果没有( 无信号),则强制杀死 if(WAIT_TIMEOUT == WaitForSingleObject(m_hThread,100)) TerminateThread(m_hThread,-1); if(m_hThread) { CloseHandle(m_hThread);//关闭句柄 m_hThread = NULL; } m_proctrl.SetPos(0);//进度条归零 }
六 . 实现进程间通信(一个进程可以控制另一个进程中进度条的停止)
进程间用时间进行通信,事件也是系统内核,HANDLE句柄类型。
在Dialog类中定义一个HANDLE hSignal;
hSignal = CreateEvent(NULL,//安全属性 TRUE,//复位属性(自动/手动)TRUE为人工,FALSE为自动 FALSE,//初始化(无信号) _T("Event"));//名字
在线程执行函数中
DWORD WINAPI ThreadProc(LPVOID lpParameter)//线程要执行的函数 { CThreadDlg* pthis = (CThreadDlg*)lpParameter; while(1) { if(WAIT_OBJECT_0 == WaitForSingleObject(pthis->hSignal , 100)) //等待100ms,事件有信号则返回 break; pthis->proctrl.StepIt(); Sleep(100); } return 0; }
在go按钮中
if(!hThread) { ResetEvent(hSignal);//重置信号(自动则不需要) hThread = CreateThread(//多线程,并行:同时执行 NULL, 0,//线程栈大小,默认为1M &ThreadProc,//进程执行的函数 this,//传入线程的参数 0,//立即执行, CREATE_SUSPENDED 挂起执行 0//进程ID ); }
在stop按钮中
void CThreadDlg::OnBnClickedStop()//杀死线程 { //将事件设为有信号 SetEvent(hSignal); if(hThread) { CloseHandle(hThread); hThread = 0; } proctrl.SetPos(0); }
新建项目,放置一个按钮,按钮功能为让另一个进程的进度条线程退出
HANDLE hEvent = OpenEvent(EVENT_ALL_ACCESS , FALSE , _T("Event"));//第一个为权限,第三个为事件名称(唯一) if(hEvent) SetEvent(hEvent);
七 . 线程的基本状态:
阻塞---1--->就绪----2--->执行 1. 获得I/O资源 2.获得时间片
阻塞<---3----就绪<---4---执行 3.不存在,因为就绪态没办法执行到阻塞 4.时间片用完
阻塞----5---->执行 5.不存在
阻塞<-----6----执行 6.缺少I/O资源