Windows C线程和MFC线程 C多线程 创建一个多线程的项目
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 #include <stdio.h> #include <windows.h> #include <conio.h> DWORD WINAPI ThreadFunc (LPVOID lpParam) { for (int i = 0 ; i < 0x100000 ; ++i) { Sleep (10 ); char szMsg[80 ]; wsprintf (szMsg, "Parameter = %d\r\n." , GetCurrentThreadId ()); printf (szMsg); } return 0 ; } VOID main (VOID) { DWORD dwThreadId, dwThrdParam = 1 ; HANDLE hThread; char szMsg[80 ]; for (int i = 0 ; i < 4 ; ++i) { hThread = CreateThread ( NULL , 0 , ThreadFunc, &dwThrdParam, 0 , &dwThreadId); } if (hThread == NULL ) { wsprintf (szMsg, "CreateThread failed." ); MessageBox (NULL , szMsg, "main" , MB_OK); } else { _getch(); CloseHandle (hThread); } }
C语言在开始的时候没有多线程的处理方式而是通过全局变量来实现 就会导致同步问题的产生 现在好像已经解决了 跑起来没什么问题
开始时解决的多线程的问题通过_beginthread
和_beginthreadex
二者将全局变量移到了线程局部存储空间 - tls
tls - thread local storage
1 2 3 4 5 6 7 TlsAlloc TlsFree TlsSetValue TlsGetValue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 #include <stdio.h> #include <windows.h> #include <conio.h> DWORD WINAPI ThreadFunc (LPVOID lpParam) { DWORD dwIdx = TlsAlloc(); TlsSetValue(dwIdx, (LPVOID)GetCurrentThreadId()); for (int i = 0 ; i < 0x100000 ; ++i) { Sleep(10 ); DWORD dwVal = (DWORD)TlsGetValue(dwIdx); char szMsg[80 ]; wsprintf(szMsg, "Parameter = %d.\tidx:%d \tval:%d\r\n." , GetCurrentThreadId(),dwIdx,dwVal); printf (szMsg); } TlsFree(dwIdx); return 0 ; } VOID main (VOID) { DWORD dwThreadId, dwThrdParam = 1 ; HANDLE hThread; char szMsg[80 ]; for (int i = 0 ; i < 40 ; ++i) { hThread = CreateThread( NULL , 0 , ThreadFunc, &dwThrdParam, 0 , &dwThreadId); } if (hThread == NULL ) { wsprintf(szMsg, "CreateThread failed." ); MessageBox(NULL , szMsg, "main" , MB_OK); } else { _getch(); CloseHandle(hThread); } }
运行结果:
_beginthread
和_beginthreadex
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 函数原型及参数说明: unsigned long _beginthread( void (_cdecl *start_address)(void *), unsigned stack_size, void *arglist ); unsigned long _beginthreadex( void *security, unsigned stack_size, unsigned (_stdcall *start_address)(void *), void *argilist, unsigned initflag, unsigned *thrdaddr ); 线程结束: void _endthread(void ); void _endthreadex(unsigned retval);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 #include <windows.h> #include <conio.h> #include <stdio.h> #include <process.h> unsigned int WINAPI ThreadFunc (LPVOID lpParam) { DWORD dwIdx = TlsAlloc(); TlsSetValue(dwIdx, (LPVOID)GetCurrentThreadId()); for (int i = 0 ; i < 0x100000 ; ++i) { Sleep(10 ); DWORD dwVal = (DWORD)TlsGetValue(dwIdx); char szMsg[80 ]; wsprintf(szMsg, "Parameter=%d\tidx:%d\tval:%d\r\n" , GetCurrentThreadId(), dwIdx, dwVal); printf (szMsg); } TlsFree(dwIdx); return 0 ; } int main () { unsigned int dwThreadId, dwThrdParam = 1 ; HANDLE hThread; char szMsg[80 ]; for (int i = 0 ; i < 80 ; ++i) { hThread = (HANDLE)_beginthreadex( NULL , 0 , ThreadFunc, &dwThrdParam, 0 , &dwThreadId ); } if (hThread == NULL ) { wsprintf(szMsg, "CreateThread failed." ); MessageBox(NULL , szMsg, "main" , MB_OK); } else { _getch(); CloseHandle(hThread); } return 0 ; }
MT
M:多线程 T:静态库
MTd
M:多线程 T:静态库 d: debug(调试版)
MD
M:多线程 D:动态库
mDd
M:多线程 D:动态库 d: debug(调试版)
MFC多线程 AfxBeginThread
1 2 3 4 5 6 7 8 9 10 11 12 13 14 CWinThread* AfxBeginThread ( AFX_THREADPROC pfnThreadProc, LPVOID pParam, int nPriority = THREAD_PRIORITY_NORMAL, UINT nStackSize = 0 , DWORD dwCreateFlags = 0 , LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL ) ;CWinThread* AfxBeginThread ( CRuntimeClass* pThreadClass, int nPriority = THREAD_PRIORITY_NORMAL, UINT nStackSize = 0 , DWORD dwCreateFlags = 0 , LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL ) ;
参数4:*dwCreateFlags
* 指定一个用于控制线程创建的额外标志。 此标志可以包含两个值之一:
CREATE_SUSPENDED
以 1 的挂起计数启动线程。 如果要在线程开始运行之前初始化 CWinThread
对象的任何成员数据(例如 m_bAutoDelete
或派生类的任何成员),请使用 CREATE_SUSPENDED
。 初始化完成后,使用 CWinThread::ResumeThread
启动线程运行。 在调用 CWinThread::ResumeThread
之前,线程不会执行。
0 创建后立即启动线程。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 #include "pch.h" #include "framework.h" #include "MFCThread.h" #include "MFCThreadDlg.h" #include "afxdialogex.h" #ifdef _DEBUG #define new DEBUG_NEW #endif class CAboutDlg : public CDialogEx{ public : CAboutDlg (); #ifdef AFX_DESIGN_TIME enum { IDD = IDD_ABOUTBOX }; #endif protected : virtual void DoDataExchange (CDataExchange* pDX) ; 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 ()CMFCThreadDlg::CMFCThreadDlg (CWnd* pParent ) : CDialogEx (IDD_MFCTHREAD_DIALOG, pParent) { m_hIcon = AfxGetApp ()->LoadIcon (IDR_MAINFRAME); } void CMFCThreadDlg::DoDataExchange (CDataExchange* pDX) { CDialogEx::DoDataExchange (pDX); } BEGIN_MESSAGE_MAP (CMFCThreadDlg, CDialogEx) ON_WM_SYSCOMMAND () ON_WM_PAINT () ON_WM_QUERYDRAGICON () ON_BN_CLICKED (IDC_BUTTON1, &CMFCThreadDlg::OnBnClickedButton1) END_MESSAGE_MAP ()BOOL CMFCThreadDlg::OnInitDialog () { CDialogEx::OnInitDialog (); ASSERT ((IDM_ABOUTBOX & 0xFFF0 ) == IDM_ABOUTBOX); ASSERT (IDM_ABOUTBOX < 0xF000 ); CMenu* pSysMenu = GetSystemMenu (FALSE); if (pSysMenu != nullptr ) { 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); return TRUE; } void CMFCThreadDlg::OnSysCommand (UINT nID, LPARAM lParam) { if ((nID & 0xFFF0 ) == IDM_ABOUTBOX) { CAboutDlg dlgAbout; dlgAbout.DoModal (); } else { CDialogEx::OnSysCommand (nID, lParam); } } void CMFCThreadDlg::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 CMFCThreadDlg::OnQueryDragIcon () { return static_cast <HCURSOR>(m_hIcon); } UINT MyControllingFunction (LPVOID pParam) { CString strFmt; strFmt.Format ("hello mfc thread %d" , GetCurrentThreadId ()); AfxMessageBox (strFmt); return 0 ; } void CMFCThreadDlg::OnBnClickedButton1 () { AfxBeginThread (MyControllingFunction, NULL ); }
运行结果:
添加MFC类
继承CWinThread
添加类向导
线程跑代码的主体
CMyThread.h:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 #pragma once #define MM_TEST WM_USER+1 class CMyThread : public CWinThread{ DECLARE_DYNCREATE (CMyThread) protected : CMyThread (); virtual ~CMyThread (); public : virtual BOOL InitInstance () ; virtual int ExitInstance () ; protected : DECLARE_MESSAGE_MAP () public : virtual int Run () ; afx_msg void OnMmTest (WPARAM wParam, LPARAM lParam) ; };
CMyThread.cpp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 #include "pch.h" #include "MFCThread.h" #include "CMyThread.h" IMPLEMENT_DYNCREATE (CMyThread, CWinThread)CMyThread::CMyThread () { } CMyThread::~CMyThread () { } BOOL CMyThread::InitInstance () { return TRUE; } int CMyThread::ExitInstance () { return CWinThread::ExitInstance (); } BEGIN_MESSAGE_MAP (CMyThread, CWinThread) ON_THREAD_MESSAGE (MM_TEST, &CMyThread::OnMmTest) END_MESSAGE_MAP ()int CMyThread::Run () { AfxMessageBox ("Run" ); return CWinThread::Run (); } void CMyThread::OnMmTest (WPARAM wParam, LPARAM lParam) { AfxMessageBox ("OnMnTest" ); }
添加两个按钮来跑线程和发消息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #include "CMyThread.h" CWinThread* pThread = NULL ; void CMFCThreadDlg::OnBnClickedButton2 () { pThread = AfxBeginThread (RUNTIME_CLASS (CMyThread)); } void CMFCThreadDlg::OnBnClickedButton3 () { pThread->PostThreadMessage (MM_TEST, NULL , NULL ); }
运行效果: 先点击方法二运行 再点击发消息
这种方式与createthread
类似 但是可以接收消息
ini文件操作 .ini文件是Windows系统配置文件所采用的存储格式,统管Windows的各项配置
ini配置文件由节、键、值组成。
例如:
等号左边为参数 右边为值 [。。。]所代表的就是节
在节声明后的所有参数都属于该节。一个节没有明显的结束标识符,一个节的开始就是上一个节的结束或者是文件结束。
ini文件操作相关的API
以WritePrivateProfileString
为例
创建一个控制台项目
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 #include <iostream> #include <Windows.h> using namespace std;int main () { DWORD dwRet = WriteProfileString ("CR40" ,"年龄" ,"10" ); BOOL bRet = WritePrivateProfileString ("CR40" , "年龄" , "10" ,"test.ini" ); cout << "Hello World!\n" ; }
获取自身工作目录:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #include <windows.h> #include <iostream> using namespace std;int main () { char szPath[MAX_PATH] = {}; GetCurrentDirectory (MAX_PATH, szPath); DWORD dwRet = WriteProfileString ("CR40" , "年龄" , "10" ); char szIniPath[MAX_PATH] = {}; wsprintf (szIniPath, "%s\\test.ini" , szPath); BOOL bRet = WritePrivateProfileString ("CR40" , "年龄" , "12" , "test.ini" ); if (!bRet) { cout << "写入失败" << endl; } std::cout << "Hello World!\n" ; }
不带Private的操作的是系统配置文件(win.ini),带Private的是操作程序自己的配置文件,注意文件名给全路径
注册表 在运行窗口中输入regedit便可以打开注册表
创建指定的注册表项。 如果注册表项已存在于注册表中,则函数将打开它。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 #include <windows.h> #include <iostream> using namespace std;int main () { HKEY h361 = NULL ; LSTATUS nRet = RegCreateKey (HKEY_CURRENT_USER, "Software\\361" , &h361); if (nRet != ERROR_SUCCESS) { return 0 ; } }
设置指定注册表项的默认值或未命名值的数据。 数据必须是文本字符串。
参数1:hKey
打开的注册表项的句柄。
参数2:lpSubKey
hKey 参数的子项的名称。 函数设置指定子项的默认值。
参数3:dwType
要存储的信息的类型。
参数4: lpData
要存储的数据。 此参数不能为 NULL 。
添加:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 #include <windows.h> #include <iostream> using namespace std;int main () { HKEY h361 = NULL ; LSTATUS nRet = RegCreateKey (HKEY_CURRENT_USER, "Software\\361" , &h361); if (nRet != ERROR_SUCCESS) { return 0 ; } char szData[] = { "the" }; nRet = RegSetValueEx (h361, "mmm" , 0 , REG_SZ, (LPBYTE)szData, sizeof (szData)); if (nRet != ERROR_SUCCESS) { return 0 ; } DWORD dwValue = 1 ; nRet = RegSetValueEx (h361, "no" , 0 , REG_DWORD, (LPBYTE)&dwValue, sizeof (dwValue)); if (nRet != ERROR_SUCCESS) { return 0 ; } }
删除子键:
参数1:当前打开的父键句柄 参数2:将要删除的子键名称
361整个都被删除了
删除值:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 #include <windows.h> #include <iostream> using namespace std;int main () { HKEY h361 = NULL ; LSTATUS nRet = RegCreateKey (HKEY_CURRENT_USER, "Software\\361" , &h361); if (nRet != ERROR_SUCCESS) { return 0 ; } char szData[] = { "the" }; nRet = RegSetValueEx (h361, "mmm" , 0 , REG_SZ, (LPBYTE)szData, sizeof (szData)); if (nRet != ERROR_SUCCESS) { return 0 ; } DWORD dwValue = 1 ; nRet = RegSetValueEx (h361, "no" , 0 , REG_DWORD, (LPBYTE)&dwValue, sizeof (dwValue)); if (nRet != ERROR_SUCCESS) { return 0 ; } nRet = RegDeleteValue (h361, "mmm" ); RegCloseKey (h361); nRet = RegDeleteKey (HKEY_CURRENT_USER, "Software\\361" ); if (nRet != ERROR_SUCCESS) { return 0 ; } }
检索与打开的注册表项关联的指定值名称的类型和数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 #include <windows.h> #include <iostream> using namespace std;#define MAX_VALUE_NAME 1024 void QueryKey (HKEY hKey) { CHAR achKey[MAX_PATH]; CHAR achClass[MAX_PATH] = TEXT ("" ); DWORD cchClassName = MAX_PATH; DWORD cSubKeys = 0 ; DWORD cbMaxSubKey = 0 ; DWORD cchMaxClass = 0 ; DWORD cValues = 0 ; DWORD cchMaxValue = 0 ; DWORD cbMaxValueData = 0 ; DWORD cbSecurityDescriptor = 0 ; FILETIME ftLastWriteTime; DWORD i = 0 , j = 0 , retCode = 0 , retValue = 0 ; CHAR achValue[MAX_VALUE_NAME]; DWORD cchValue = MAX_VALUE_NAME; CHAR achBuff[80 ]; RegQueryInfoKey ( hKey, achClass, &cchClassName, NULL , &cSubKeys, &cbMaxSubKey, &cchMaxClass, &cValues, &cchMaxValue, &cbMaxValueData, &cbSecurityDescriptor, &ftLastWriteTime); for (i = 0 , retCode = ERROR_SUCCESS; retCode == ERROR_SUCCESS; i++) { DWORD dwNamelen = MAX_PATH; retCode = ::RegEnumKeyEx (hKey, i, achKey, &dwNamelen, NULL , NULL , NULL , &ftLastWriteTime); if (retCode == (DWORD)ERROR_SUCCESS) { printf ("Key:%s\r\n" , achKey); } } if (cValues) { for (j = 0 , retValue = ERROR_SUCCESS; j < cValues; j++) { cchValue = MAX_VALUE_NAME; achValue[0 ] = '\0' ; retCode = ::RegEnumValue (hKey, j, achValue, &cchValue, NULL , NULL , NULL , NULL ); if (retValue != (DWORD)ERROR_SUCCESS && retValue != ERROR_INSUFFICIENT_BUFFER) { wsprintf (achBuff, "Line:%d 0 based index = %d,retValue = %d," "ValueLen = %d" , __LINE__, j, retValue, cchValue); printf (achBuff); } } } } int main () { HKEY h361 = NULL ; LSTATUS nRet = RegCreateKey (HKEY_CURRENT_USER, "Software" , &h361); if (nRet != ERROR_SUCCESS) { return 0 ; } QueryKey (h361); }
运行结果: