实习随手记-MFC多线程分解复制文件

来源:互联网 发布:大数据彩票预测王律强 编辑:程序博客网 时间:2024/05/22 12:19
//==================================在MFC 对应的 Dlg.cpp 中编写,前面都是固定生成的东西============// MFCApplication1Dlg.cpp : 实现文件//#include "stdafx.h"#include "MFCApplication1.h"#include "MFCApplication1Dlg.h"#include "afxdialogex.h"#ifdef _DEBUG#define new DEBUG_NEW#endif// 用于应用程序“关于”菜单项的 CAboutDlg 对话框class CAboutDlg : public CDialogEx{public:CAboutDlg();// 对话框数据#ifdef AFX_DESIGN_TIMEenum { IDD = IDD_ABOUTBOX };#endifprotected:virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持// 实现protected:DECLARE_MESSAGE_MAP()};CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX){}void CAboutDlg::DoDataExchange(CDataExchange* pDX){CDialogEx::DoDataExchange(pDX);}BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)END_MESSAGE_MAP()// CMFCApplication1Dlg 对话框CMFCApplication1Dlg::CMFCApplication1Dlg(CWnd* pParent /*=NULL*/): CDialogEx(IDD_MFCAPPLICATION1_DIALOG, pParent){m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);}void CMFCApplication1Dlg::DoDataExchange(CDataExchange* pDX){CDialogEx::DoDataExchange(pDX);DDX_Control(pDX, IDC_PROGRESS1, m_progress);}BEGIN_MESSAGE_MAP(CMFCApplication1Dlg, CDialogEx)ON_WM_SYSCOMMAND()ON_WM_PAINT()ON_WM_QUERYDRAGICON()ON_BN_CLICKED(IDOK, &CMFCApplication1Dlg::OnBnClickedOk)ON_BN_CLICKED(IDC_BUTTON1, &CMFCApplication1Dlg::OnBnClickedButton1)ON_BN_CLICKED(IDC_OPEN_BUTTON, &CMFCApplication1Dlg::OnBnClickedOpenButton)ON_BN_CLICKED(IDCANCEL, &CMFCApplication1Dlg::OnBnClickedCancel)END_MESSAGE_MAP()// CMFCApplication1Dlg 消息处理程序BOOL CMFCApplication1Dlg::OnInitDialog(){CDialogEx::OnInitDialog();// 将“关于...”菜单项添加到系统菜单中。// IDM_ABOUTBOX 必须在系统命令范围内。ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);ASSERT(IDM_ABOUTBOX < 0xF000);CMenu* pSysMenu = GetSystemMenu(FALSE);if (pSysMenu != NULL){BOOL bNameValid;CString strAboutMenu;bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);ASSERT(bNameValid);if (!strAboutMenu.IsEmpty()){pSysMenu->AppendMenu(MF_SEPARATOR);pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);}}// 设置此对话框的图标。  当应用程序主窗口不是对话框时,框架将自动//  执行此操作SetIcon(m_hIcon, TRUE);// 设置大图标SetIcon(m_hIcon, FALSE);// 设置小图标// TODO: 在此添加额外的初始化代码m_progress.SetRange(0, 100);m_progress.SetPos(0);return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE}void CMFCApplication1Dlg::OnSysCommand(UINT nID, LPARAM lParam){if ((nID & 0xFFF0) == IDM_ABOUTBOX){CAboutDlg dlgAbout;dlgAbout.DoModal();}else{CDialogEx::OnSysCommand(nID, lParam);}}// 如果向对话框添加最小化按钮,则需要下面的代码//  来绘制该图标。  对于使用文档/视图模型的 MFC 应用程序,//  这将由框架自动完成。void CMFCApplication1Dlg::OnPaint(){if (IsIconic()){CPaintDC dc(this); // 用于绘制的设备上下文SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);// 使图标在工作区矩形中居中int cxIcon = GetSystemMetrics(SM_CXICON);int cyIcon = GetSystemMetrics(SM_CYICON);CRect rect;GetClientRect(&rect);int x = (rect.Width() - cxIcon + 1) / 2;int y = (rect.Height() - cyIcon + 1) / 2;// 绘制图标dc.DrawIcon(x, y, m_hIcon);}else{CDialogEx::OnPaint();}}//当用户拖动最小化窗口时系统调用此函数取得光标//显示。HCURSOR CMFCApplication1Dlg::OnQueryDragIcon(){return static_cast<HCURSOR>(m_hIcon);}//=========================================多线程相关代码操作(开始)=======================================//DWORD dwThreadID[10];                   // 线程ID//HANDLE hThread[10];                   // 线程句柄HANDLE  g_hThreadEvent;CRITICAL_SECTION  g_csThreadCode; int THREAD_NUM ; //子线程个数FILE *fp, *fout;long size, one_size,last_size;// //你可以 更改大小volatile long g_nNum; //全局资源//HANDLE  g_hThreadParameter;struct THREAD_INFO {int sumnum;int num;};THREAD_INFO Info;DWORD WINAPI Fun(LPVOID lpParam){//由于创建线程是要一定的开销的,所以新线程并不能第一时间执行到这来 THREAD_INFO* pInfo = (THREAD_INFO*)lpParam; //线程获取传来的结构体参数Sleep(50);SetEvent(g_hThreadEvent); //触发事件EnterCriticalSection(&g_csThreadCode);//进入各子线程互斥区域      //------------------------进行复制工作(需要将文件进行分块)----------------------     // 全局变量Sleep(0);fseek(fp, pInfo->num*one_size, SEEK_SET);//移动到要复制的位置fseek(fout, pInfo->num*one_size, SEEK_SET);//移动到要复制的位置//若1个子线程if (pInfo->sumnum == 1){char* buff;  //开缓存buff = (char*)malloc(sizeof(char)*one_size);memset(buff, 0, sizeof(char)*one_size);//读fread(buff, 1, one_size, fp);//写fwrite(buff, 1, one_size, fout);//关缓存free(buff);buff = NULL;//回文件指针rewind(fp);rewind(fout);}//若多个子线程else {if (pInfo->num < pInfo->sumnum - 1){char* buff;  //开缓存buff = (char*)malloc(sizeof(char)*one_size);memset(buff, 0, sizeof(char)*one_size);//读fread(buff, 1, one_size, fp);//写fwrite(buff, 1, one_size, fout);//关缓存free(buff);buff = NULL;//回文件指针rewind(fp);rewind(fout);}else {char* buff;  //开缓存buff = (char*)malloc(sizeof(char)*last_size);memset(buff, 0, sizeof(char)*last_size);//读fread(buff, 1, last_size, fp);//写fwrite(buff, 1, last_size, fout);//关缓存free(buff);buff = NULL;//回文件指针rewind(fp);rewind(fout);}}//int pos = g_nNum;//m_progress.SetPos(pos*100/THREAD_NUM); //设置进度条的位置g_nNum++; //------------------------------------------------------------------------------LeaveCriticalSection(&g_csThreadCode);//离开互斥区return 0;}//“拷贝”按钮的响应void CMFCApplication1Dlg::OnBnClickedOk(){// TODO: 在此添加控件通知处理程序代码//接收编辑框输入设置里的“线程数”和“路径”g_nNum = 0;CString str;UpdateData();THREAD_NUM = GetDlgItemInt(IDC_THREADNUM_EDIT, NULL, 1);  //若看做有符号数,则bSigned为1,返回值直接以int类型去接收GetDlgItem(IDC_OPEN_EDIT)->GetWindowText(str);LPCTSTR src = str.GetString();//路径转换成窄字符DWORD dwNum = WideCharToMultiByte(CP_OEMCP, NULL, src, -1, NULL, 0, NULL, FALSE);//计算这个UTF8实际有几个字节组成char* psText = new char[dwNum];if (!psText){delete[]psText;}WideCharToMultiByte(CP_OEMCP, NULL, src, -1, psText, dwNum, NULL, FALSE);fp = fopen(psText, "rb");//源文件if (fp == NULL) { AfxMessageBox(_T("源文件读取失败")); return ; }fseek(fp, 0, SEEK_END); // non-portablesize = ftell(fp);//得到源文件大小rewind(fp);//若1个子线程if (THREAD_NUM ==1 ){one_size = size ;//得到整块的大小last_size = 0;//分完块不够一整块的最后小块的大小}//若多个子线程else if (THREAD_NUM > 1){one_size = size/ (THREAD_NUM-1);//得到整块的大小last_size = size% (THREAD_NUM - 1);//分完块不够一整块的最后小块的大小}fout = fopen("copy.txt", "wb+");//目标文件还有为她开出与源文件同大小的空间char* buffdet; //开缓存buffdet = (char*)malloc(sizeof(char)*size);memset(buffdet, 0, sizeof(char)*size);fwrite(buffdet, 1, size, fout);free(buffdet);buffdet = NULL;rewind(fout);g_hThreadEvent = CreateEvent(NULL, FALSE, FALSE, NULL);InitializeCriticalSection(&g_csThreadCode);HANDLE   hThread[20];           // 线程句柄CString strtime;long t1 = GetTickCount();//程序段开始前取得系统运行时间(ms)for (int i = 0; i < THREAD_NUM; i++){  //把第i个线程要处理的文件块内容传递过去Info.num = g_nNum;Info.sumnum = THREAD_NUM;hThread[i] = CreateThread(NULL, 0, Fun, &Info, 0, NULL);//等子线程接收到参数时主线程可能改变了这个i的值WaitForSingleObject(g_hThreadEvent, INFINITE); //等待事件被触发}// //保证子线程已全部运行结束WaitForMultipleObjects(THREAD_NUM, hThread, TRUE, INFINITE);   CloseHandle(g_hThreadEvent);DeleteCriticalSection(&g_csThreadCode);fclose(fp);fclose(fout);long t2 = GetTickCount();//程序段结束后取得系统运行时间(ms)  strtime.Format(_T("拷贝时间: %ld ms"), t2 - t1);//前后之差即程序运行时间  delete[]psText;AfxMessageBox(strtime);}void CMFCApplication1Dlg::OnBnClickedButton1(){// TODO: 在此添加控件通知处理程序代码//TerminateThread(hThread,-1);//WaitForSingleObject(hThread, INFINITE);//等待单个线程(线程耗时很长)彻底推出}//"打开文件"按钮响应void CMFCApplication1Dlg::OnBnClickedOpenButton(){// TODO: 在此添加控件通知处理程序代码// 设置过滤器   TCHAR szFilter[] = _T("文本文件(*.txt)|*.txt|所有文件(*.*)|*.*||");// 构造打开文件对话框   CFileDialog fileDlg(TRUE, _T("txt"), NULL, 0, szFilter, this);CString strFilePath;// 显示打开文件对话框   if (IDOK == fileDlg.DoModal()){// 如果点击了文件对话框上的“打开”按钮,则将选择的文件路径显示到编辑框里   strFilePath = fileDlg.GetPathName();SetDlgItemText(IDC_OPEN_EDIT, strFilePath);}}void CMFCApplication1Dlg::OnBnClickedCancel(){// TODO: 在此添加控件通知处理程序代码CDialogEx::OnCancel();}

原创粉丝点击