操作系统与网络 2019-1-31

1.进度条

1.1 我们创建一个基于对话框的MFC应用程序

1.给对话框添加一个 Progress Control 控件,添加一个 安装 按钮;
2.给 安装 按钮添加事件处理函数,该函数是为了当我们点击 安装 按钮时,进度条能够开始跑起来;
3.给进度条添加一个变量: CProgressCtrl m_process_ctrl ;
4.使用 SetIt 函数来使进度条跑起来;

void CThreadDlg::OnBnClickedButton1()
{
	// 1. 让进度条动起来
	m_process_ctrl.SetStep(1);			// 设置步长
	while(1)
	{
		m_process_ctrl.StepIt();
		::Sleep(200);
	}
}

1.2 只让进度条跑一截距离,而不让其跑完

1.当进度条的位置大于某个值时将其置零

void CThreadDlg::OnBnClickedButton1()
{
	// 2. 让进度条动起来
	m_process_ctrl.SetStep(1);			// 设置步长
	while(1)
	{
		if(m_process_ctrl.GetPos() > 50)
			m_process_ctrl.SetPos(0);
		m_process_ctrl.StepIt();
		::Sleep(200);
	}
}

1.3 我们发现在这个函数运行过程中,我们无法拖动进度条窗口

1.这是因为我们在处理消息的过程中会一直停留在 CThreadDlg::OnBnClickedButton1 消息中,因为我们在这个函数中写了死循环;
2.我们在循环中设置一个消息来接受其他消息就可以拖拽对话框了;

void CThreadDlg::OnBnClickedButton1()
{
	// 3. 在进度条动的过程中,可以拖拽对话框
	m_process_ctrl.SetStep(1);
	while (TRUE)
	{
		m_process_ctrl.StepIt();
		::Sleep(200);

		// 接受其他的消息
		MSG msg;
		::GetMessage(&msg, 0, 0, 0);
		if(!AfxPreTranslateMessage(&msg))				// 预处理消息
		{
			::TranslateMessage(&msg);
			::DispatchMessage(&msg);
		}
	}
}

3.完成上述代码后,我们又发现一个问题:当我们鼠标在对话框上移动时进度条才走,否则进度条还是不动,这个原因是 GetMessage 函数是阻塞的,也就是说它不接受到消息就会一直停在这一行代码;
4.我们使用 PeekMessage() 函数来非阻塞获取消息;

void CThreadDlg::OnBnClickedButton1()
{
	// 3. 在进度条动的过程中,可以拖拽对话框
	m_process_ctrl.SetStep(1);
	while (TRUE)
	{
		m_process_ctrl.StepIt();
		::Sleep(200);

		// 接受其他的消息
		MSG msg;
		// ::GetMessage(&msg, 0, 0, 0);
		::PeekMessage(&msg, 0, 0, 0, PM_REMOVE);
		if(!AfxPreTranslateMessage(&msg))				// 预处理消息
		{
			::TranslateMessage(&msg);
			::DispatchMessage(&msg);
		}
	}
}

2.线程

2.1 线程:轮换时间片的基本单位,进程中的执行单元

2.2 并发:多个线程交替执行

2.3 并行:多个线程同时执行

2.4 线程的组成部分

1.线程堆栈:存放局部临时资源
2.线程内核对象:计数器,挂起计数器,信号

3.使用多线程完成进度条

3.1 创建一个线程

1.使用函数 ::CreateThread 函数创建进程;

void CThreadDlg::OnBnClickedButton1()
{
	if(thread_handle != 0)
	{
		return;
	}
	HANDLE thread_handle = ::CreateThread(
		0,							// 安全属性
		0,							// 线程栈的大小
		&CThreadDlg::ThreadProc,	// 线程处理函数
		this,						// 给线程处理函数传递的参数
		0,							// 创建的线程的状态, 0 代表立即运行
		0							// 线程ID
		);
	if(thread_handle == 0)
	{
		MessageBox("线程创建失败");
	}
}

2.其中的线程处理函数是一个静态函数: static DWORD WINAPI ThreadProc(In LPVOID lpParameter) ;
3.为了使非静态成员能够在静态函数中调用,我们获取主对话框的指针: CThreadDlg* pThis = (CThreadDlg*)lpParameter ;

// 线程处理函数(要用线程做什么事情)
DWORD WINAPI CThreadDlg::ThreadProc(_In_ LPVOID lpParameter)
{
	CThreadDlg* pThis = (CThreadDlg*)lpParameter;
	pThis->m_process_ctrl.SetStep(1);
	while (pThis->m_quit_thread_flag)
	{
		pThis->m_process_ctrl.StepIt();
		::Sleep(200);							// 让出 时间片 函数
	}
	return 0;
}

4.完成上述操作即可通过新创建的线程来跑进度条。

3.2 暂停 按钮

1.给对话框添加一个 暂停 按钮;
2.在该函数中挂起线程,首先将线程的句柄定义为类成员;

// 暂停让进度条动
void CThreadDlg::OnBnClickedButton2()
{
	if(thread_handle == 0)
		return;
	// 首先将线程的句柄定义为类成员
	DWORD dwSuspendCount = SuspendThread(thread_handle);	// 返回的是挂起之前的线程的个数
	TRACE("挂起计数:%d\n", dwSuspendCount);
}

3.3 恢复 按钮

1.给对话框添加一个 恢复 按钮;
2.在该按钮处理函数中将挂起的线程重新运行;

// 继续让进度条动
void CThreadDlg::OnBnClickedButton3()
{
	if(thread_handle == 0)
		return;
	DWORD dwResumeCount = ResumeThread(thread_handle);
	TRACE("重新运行计数:%d\n", dwResumeCount);
}

3.4 结束线程 按钮

1.给对话框添加一个 结束线程 按钮;
2.给主对话框类添加一个成员: bool m_quit_thread_flag ,初始化为 true ;
3.将静态函数中的循环的条件更改为 m_quit_thread_flag ;
4.当点击 结束线程 时,将 m_quit_thread_flag 改为 false ;

// 结束按钮
void CThreadDlg::OnBnClickedButton4()
{
	// 结束目前分两种情况
	// 1. 改变flag可以退出
	m_quit_thread_flag = false;
	::CloseHandle(thread_handle);
	thread_handle = 0;
}

5.改变flag无法退出(比如循环中又套了一个循环),这时需要直接终止线程;

// 结束按钮
void CThreadDlg::OnBnClickedButton4()
{
	// 结束目前分两种情况
	// 1. 改变flag可以退出
	m_quit_thread_flag = false;

	// 2. 改变flag无法退出(比如循环中又套了一个循环)
	if(::WaitForSingleObject(thread_handle, 10) == WAIT_TIMEOUT)	// 等待10毫秒超时
	{
		// 强制终止线程
		::TerminateThread(thread_handle, -1);						// 退出码给-1为了与正常退出进行区分
		::CloseHandle(thread_handle);
		thread_handle = 0;
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值