MFC多线程编程
来源:互联网 发布:k8网络分销平台 编辑:程序博客网 时间:2024/06/16 21:04
MFC多线程开发
线程创建函数
HANDLE CreateThread(
LPSECURITY_ATTRIBUTESlpThreadAttribute, //指向SECURITY_ATTRIBUTES结构体的指针
DWORD dwStackSize, //设置线程初始栈的大小(页面大小的整数//倍)默认为调用该函数的线程相同的栈空间大小
LPTHREAD_START_ROUTINElpStartAddress, //新线程入口函数的指针
LPVOID lpParameter, //命令行参数
DWORD dwCreationFlags, //设置控制线程创建后状态的标记
LPDWORD lpThreadId //接收线程ID
);
CloseHandle()
当不需要线程句柄时,将其关闭,让这个线程内核对象的引用减1,当引用计数为0时,系统释放该线程内核对象
线程由线程内核对象和线程栈组成,在创建它的进程环境中运行,可随意访问
进程内核对象,进程地址空间
DWORD WINAPI ThreadProc(LPVOID lpParameter);
在程序定义一个函数作为新线程的入口函数。函数名任意,但函数类型声明格式固定
Void Sleep(DWORD dwMilliseconds);
线程同步
利用互斥对象实现线程同步
HANDLE CreateMutex( //mutex互斥内核对象,当前拥有互斥对象的线程ID
//和指明拥有的次数的计数器
LPSECURITY_ATTRIBUTESlpMutexAttributes,
BOOL bInitialOwner, //指定互斥对象初始的拥有者
LPCTSTR lpName //名称
)
BOOL ReleaseMutex(HANDLE hMutex); //释放该对象的所有权,使其处于已通知状态实为//递减计数器的值
DWORD WaitForSingleObject(HANDLEhHandle,DWORD dwMilliseconds);
主动请求共享对象的使用权,dwmiliseconds为等待时间指定对象为有信号状态返回
返回值 WAIT_OBJECT_0 WAIT_TIMEOUT WAIT_ABANDONED
对于互斥对象,谁拥有谁释放
操作系统一旦发现线程已终止,自动将其拥有的互斥对象的线程ID设为0,计数器归0
保证应用程序只有一个实例(进程吗??)运行
GetLastError()函数 ERROR_ALREADY_EXISTS表明先前已经创建了这个命名的互斥对象
线程的时间片
很久以前,接触一个项目,看到一个while(1)死循环,但又发现程序经常跳出while去执行另外一段程序,甚为疑虑。其实,在多线程模式下,这是可能的,下面的程序就不会一直陷入main的while(1)循环:
1. #include<stdio.h>
2. #include <windows.h>
3. DWORD WINAPI ThreadFun(LPVOID pM)
4. {
5. while(1)
6. {
7. printf("thread\n");
8. exit(0);
9. }
10.
11. return 0;
12. }
13.
14. int main()
15.{
16. HANDLE handle = CreateThread(NULL,0, ThreadFun, NULL, 0, NULL);
17. CloseHandle(handle);
18.
19. while(1)
20. {
21. printf("mainthread\n");
22. }
23.
24. return 0;
25.}
运行结果如下:
解释:系统为每个线程都分配有一定时间的时间片,当主线程一直在循环时,如果时间片的时间到了,系统会选择执行其他的线程。当主线程暂停时,系统由执行其他线程返回到执行主线程时是从哪里进入的,是重新又main进入,还是从暂停处进入?当然是暂停处。
exit(0) 退出进程,如果不退出,当线程ThreadFun时间片到了会继续执行主线程的循环
线程同步
*互斥对象实现线程同步*/#include <windows.h>#include <iostream>using namespace std;DWORD WINAPI Fun1Proc(LPVOID lpParameter //thread data);DWORD WINAPI Fun2Proc(LPVOID lpParameter //thread data);int index=0;int tickets=100;HANDLE hMutex;void main(){HANDLE hThread1;HANDLE hThread2;hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);CloseHandle(hThread1);CloseHandle(hThread2);hMutex=CreateMutex(NULL,FALSE,NULL);if(hMutex){if(ERROR_ALREADY_EXISTS==GetLastError()){cout<<"only one instance can run!"<<endl;return;}}WaitForSingleObject(hMutex,INFINITE);ReleaseMutex(hMutex);ReleaseMutex(hMutex);//while(index++<1000)//{//cout<<"main thread is running"<<endl;////Sleep(10);//}//Sleep(10);Sleep(40000);}DWORD WINAPI Fun1Proc(LPVOID lpParameter){/*while(index++<1000)cout<<"thread1 is running"<<endl;*/while(TRUE){WaitForSingleObject(hMutex,INFINITE);if(tickets>0){Sleep(1);cout<<"thread1 sell ticket:"<<tickets--<<endl;}elsebreak;ReleaseMutex(hMutex);}return 0;}DWORD WINAPI Fun2Proc(LPVOID lpParameter){/*while(index++<1000)cout<<"thread2 is running"<<endl;*/while(TRUE){WaitForSingleObject(hMutex,INFINITE);if(tickets>0){Sleep(1);cout<<"thread2 sell ticket:"<<tickets--<<endl;}elsebreak;ReleaseMutex(hMutex);}return 0;}
利用事件对象实现线程同步
创建事件对象:
HANDLE CreateEvent( //事件对象
LPSECURITY_ATTRIBUTESlpEventAyyributes,//NULL,默认安全性
BOOLbManualReset, //真为人工重置事件对象或自动重置事件对象
BOOLbInitialState, //初始状态,真为有信号,假为无信号
LPCTSTRlpName //事件对象名称
);
设置事件对象状态
BOOL SetEvent(HANDLE hEvent);
重置事件对象状态
BOOL ResetEvent(HANDLE hEvent);
事件对象三个成员:使用计数、指明事件是自动重置还是手动重置、指明事件是通知状态还是未通知状态。
人工重置事件对象:得到通知,等待该事件对象的所有线程变为可调度线程,当线程等待到对象的所有权后,调用ResetEvent函数手动设置为无信号状态
自动重置事件对象:得到通知,只有一个等待线程变为可调度线程,系统自动将对象设置为无信号状态
*事件对象实现线程同步*/#include <windows.h>#include <iostream>using namespace std;DWORD WINAPI Fun1Proc(LPVOID lpParameter //thread data);DWORD WINAPI Fun2Proc(LPVOID lpParameter //thread data);//int index=0;int tickets=100;HANDLE hEvent;void main(){HANDLE hThread1;HANDLE hThread2;hEvent=CreateEvent(NULL,FALSE,FALSE,NULL);//hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);SetEvent(hEvent);hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);CloseHandle(hThread1);CloseHandle(hThread2);/*if(hEvent){if(ERROR_ALREADY_EXISTS==GetLastError()){cout<<"only one instance can run!"<<endl;return;}}*///WaitForSingleObject(hEvent,INFINITE);//ReleaseMutex(hEvent);//ReleaseMutex(hEvent);//while(index++<1000)//{//cout<<"main thread is running"<<endl;////Sleep(10);//}//Sleep(10);Sleep(40000);CloseHandle(hEvent);}DWORD WINAPI Fun1Proc(LPVOID lpParameter){/*while(index++<1000)cout<<"thread1 is running"<<endl;*/while(TRUE){WaitForSingleObject(hEvent,INFINITE);//ResetEvent(hEvent);if(tickets>0){Sleep(1);cout<<"thread1 sell ticket:"<<tickets--<<endl;SetEvent(hEvent);}else{break;SetEvent(hEvent);}//ReleaseMutex(hEvent);}return 0;}DWORD WINAPI Fun2Proc(LPVOID lpParameter){/*while(index++<1000)cout<<"thread2 is running"<<endl;*/while(TRUE){WaitForSingleObject(hEvent,INFINITE);//ResetEvent(hEvent);if(tickets>0){Sleep(1);cout<<"thread2 sell ticket:"<<tickets--<<endl;SetEvent(hEvent);}else{break;SetEvent(hEvent);}//ReleaseMutex(hEvent);}return 0;}
关键代码段(临界区)实现线程同步
在代码能够执行前,它必须独占对某些资源的访问权,类似于电话亭
初始化临界区对象
Void InitializeCriticalSection(LPCRITCAL_SECTIONlpCriticalSection);out类型参数
等待获得所有权?使用权
EnterCriticalSection()
释放临界区对象的所有权
LeaveCriticalSection()
删除指定临界区对象
DeleteCriticalSection()
线程死锁
线程1获得临界区对象a的所有权的同时请求临界区对象b的所有权,而同时线程2获得临界区对象b的所有权后申请临界区对象a的所有权,造成线程死锁
互斥对象和事件对象是内核对象,速度缓慢,但可在多个进程中的各个线程中进行同步;
临界区对象工作在用户态,容易进入死锁,但首选关键代码段
/*关键代码段实现线程同步*/#include <windows.h>#include <iostream>using namespace std;DWORD WINAPI Fun1Proc(LPVOID lpParameter //thread data);DWORD WINAPI Fun2Proc(LPVOID lpParameter //thread data);//int index=0;int tickets=100;CRITICAL_SECTION cs;void main(){HANDLE hThread1;HANDLE hThread2;//hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);//SetEvent(hEvent);hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);CloseHandle(hThread1);CloseHandle(hThread2);/*if(hEvent){if(ERROR_ALREADY_EXISTS==GetLastError()){cout<<"only one instance can run!"<<endl;return;}}*///WaitForSingleObject(hEvent,INFINITE);//ReleaseMutex(hEvent);//ReleaseMutex(hEvent);//while(index++<1000)//{//cout<<"main thread is running"<<endl;////Sleep(10);//}//Sleep(10);InitializeCriticalSection(&cs);Sleep(40000);DeleteCriticalSection(&cs);//CloseHandle(hEvent);}DWORD WINAPI Fun1Proc(LPVOID lpParameter){/*while(index++<1000)cout<<"thread1 is running"<<endl;*/while(TRUE){//WaitForSingleObject(hEvent,INFINITE);//ResetEvent(hEvent);EnterCriticalSection(&cs);Sleep(1);if(tickets>0){Sleep(1);cout<<"thread1 sell ticket:"<<tickets--<<endl;//SetEvent(hEvent);LeaveCriticalSection(&cs);}else{break;//SetEvent(hEvent);LeaveCriticalSection(&cs);}//ReleaseMutex(hEvent);}return 0;}DWORD WINAPI Fun2Proc(LPVOID lpParameter){/*while(index++<1000)cout<<"thread2 is running"<<endl;*/while(TRUE){//WaitForSingleObject(hEvent,INFINITE);//ResetEvent(hEvent);EnterCriticalSection(&cs);Sleep(1);if(tickets>0){Sleep(1);cout<<"thread2 sell ticket:"<<tickets--<<endl;//SetEvent(hEvent);LeaveCriticalSection(&cs);}else{break;//SetEvent(hEvent);LeaveCriticalSection(&cs);}//ReleaseMutex(hEvent);}return 0;}
- MFC多线程编程总结
- MFC多线程编程注意事项
- MFC多线程编程
- MFC多线程编程注意事项
- MFC多线程编程注意事项
- MFC多线程编程注意事项
- MFC多线程编程注意事项
- MFC多线程编程注意事项
- 多线程编程MFC
- MFC多线程编程注意事项
- MFC多线程编程注意事项
- MFC多线程编程注意事项
- MFC多线程编程
- MFC 多线程编程问题
- MFC 多线程编程
- MFC多线程编程1
- MFC多线程编程2
- MFC 多线程编程
- Wayland的前世与今生(二)------我的后半生
- spring 整合 quartz
- 进度条的实现(ProgressTimer)
- 112_容器_数据存储练习_JavaBean的介绍
- Linux 正则表达式与通配符
- MFC多线程编程
- office ENUMS
- Redis在windows下安装过程
- ScrollView的使用
- java基础总结五(方法)
- PageView的使用
- Hibernate
- 解析解与数值解的区别
- Linux 获取制定目录的文件数(递归)