吃字母游戏
TCHAR字符串操作函数:
_tcslen(str) //获得字符串长度 _tcsrchr(str, L'\\') //反向搜索获得最后一个TCHAR的位置 _stprintf(TCHAR *buffer,const TCHAR *format [,argument] ... ) //获得一个格式化字符串 _tcsdup //给一个指针分配源字符串大小的内存并从源字符串copy值 _tcstok //按标记将字符串拆分 tcscpy //拷贝字符串
1.目标
如上图;在资源文本框中输入一串字母;
点击按钮“GO”,将把字符串中的字母依次读入缓冲区;
4个消费者线程会从缓冲区中将字母读入自己的文本框中,然后会将缓冲区置0;
生产者线程在缓冲区为0时再次将后面的字句写入缓冲区;
2.大体思路
1)线程
需要一个生产者线程;用来读取资源文本框中的字符串,并按顺序将字符串中的每个字符写入缓冲区;
需要4个消费者线程;用来从缓冲区文本框中读取字符;在读取完后将缓冲区置0;
线程同步:
消费者线程需要在生产者线程将字符写入缓冲区后才能从缓冲区中读取字符;
线程互斥:
同一时刻只能有一个线程来操作缓冲区;
2)生产者
从资源文本框中读取字符串;
循环将每个字符写入缓冲区文本框;
缓冲区文本框有2个,需要循环判断,只要其中一个为0则将字符写入;写入后退出循环,开始处理下一个字符;
当字符串中的所有字符处理完后生产者线程结束;
可以获取字符串的长度来判断生产者线程结束的标志;
3)消费者
主要做三件事:
从缓冲区文本框中读取字符;
将缓冲区中的字符写入自己的文本框;
将缓冲区文本框置0告诉生产者这个缓冲区中的字符被读完了;
线程结束:
消费者线程需要在生产者将所有字符处理完,并且缓冲区中的字符全部被读完后结束;
如果线程不结束程序会卡死;
结束线程有两种方式:超过一定的等待时间、用全局变量做标记,生产者完成后修改标记;
这里用第一种方式来实现线程结束;
3.代码
#include <windows.h> #include <stdio.h> #include <tchar.h> #include "resource.h" //文本框句柄 HWND hRes; HWND hBuf[2]; HWND hTxt[4]; //临界区 CRITICAL_SECTION cs; //信号量 HANDLE hSemaphoreCust; HANDLE hSemaphoreProd; //线程句柄 HANDLE hThread[5]; //生产者线程 DWORD WINAPI ThreadProcProd(LPVOID lpParameter) { //读取资源 TCHAR szBuffer[256]; memset(szBuffer, 0, 256*sizeof(TCHAR)); ::GetWindowText(hRes, szBuffer, 256); //将字符写入到缓冲区 DWORD len = _tcslen(szBuffer); //获取字符串长度 for(int i=0;i<len;i++){ ::WaitForSingleObject(hSemaphoreProd, INFINITE); //等待生产者信号量 EnterCriticalSection(&cs); //获取令牌 TCHAR szBuf[256]; TCHAR szTmp[2]; memset(szTmp, 0, 2*sizeof(TCHAR)); memcpy(szTmp, szBuffer+i, sizeof(TCHAR)); //字符拷贝到临时缓冲区 for(int j=0;j<2;j++){ memset(szBuf, 0, 256*sizeof(TCHAR)); ::GetWindowText(hBuf[j], szBuf, 256*sizeof(TCHAR)); if(_tcscmp(szBuf, TEXT("0")) == 0 ){ //如果有有一个缓冲区为0则添加 ::SetWindowText(hBuf[j], szTmp); break; } } ::ReleaseSemaphore(hSemaphoreCust, 1, NULL); //每次放完之后释放一个消费者信号量 LeaveCriticalSection(&cs); } return 0; } //消费者线程 DWORD WINAPI ThreadProc(LPVOID lpParameter) { DWORD index = (DWORD) lpParameter; while(TRUE){ ::WaitForSingleObject(hSemaphoreCust, INFINITE); EnterCriticalSection(&cs); //获取令牌 //从缓冲区中读取字母 TCHAR szTmp[2]; memset(szTmp, 0, 2*sizeof(TCHAR)); for(int i=0;i<2;i++){ //有两个缓冲区,其中一个不为0就从那里读 ::GetWindowText(hBuf[i], szTmp, 2); if(_tcscmp(szTmp, TEXT("0")) != 0){ //写入自己的文本框 TCHAR szBuffer[256]; memset(szBuffer, 0, 256*sizeof(TCHAR)); ::GetWindowText(hTxt[index], szBuffer, 256); DWORD len = _tcslen(szBuffer); TCHAR buf[256]; memset(buf, 0 ,256*sizeof(TCHAR)); memcpy(buf,TEXT("_"), sizeof(TCHAR)); memcpy(buf+1, szTmp, sizeof(TCHAR)); memcpy(buf+2, szBuffer, len*sizeof(TCHAR)); ::SetWindowText(hTxt[index], buf); //缓冲区置0 ::SetWindowText(hBuf[i], TEXT("0")); break; } } ::ReleaseSemaphore(hSemaphoreProd, 1, NULL); LeaveCriticalSection(&cs); } return 0; } //线程函数 DWORD WINAPI ThreadBegin(LPVOID lpParameter) { hSemaphoreProd = CreateSemaphore(NULL, 2, 2, NULL); //生产者信号量,初始有2个信号 hSemaphoreCust = CreateSemaphore(NULL, 0, 2, NULL); //消费者信号量 InitializeCriticalSection(&cs); //初始化临界区 //开启消费者线程 hThread[0] = ::CreateThread(NULL, 0, ThreadProc, (void*)0, 0, NULL); hThread[1] = ::CreateThread(NULL, 0, ThreadProc, (void*)1, 0, NULL); hThread[2] = ::CreateThread(NULL, 0, ThreadProc, (void*)2, 0, NULL); hThread[3] = ::CreateThread(NULL, 0, ThreadProc, (void*)3, 0, NULL); //开启生产者线程 hThread[4] = ::CreateThread(NULL, 0, ThreadProcProd, NULL, 0, NULL); //释放信号量 ::WaitForMultipleObjects(5, hThread,TRUE,INFINITE); //当5个线程运行完后会自动进入已通知状态,此时关闭信号量 ::CloseHandle(hSemaphoreProd); ::CloseHandle(hSemaphoreProd); return 0; } //回调函数 BOOL CALLBACK MainDlgProc(HWND hDlg,UINT uMsg,WPARAM wParam,LPARAM lParam) { BOOL bRet = FALSE; switch(uMsg) { case WM_CLOSE: { EndDialog(hDlg,0); break; } case WM_INITDIALOG: { //获取文本框句柄 hRes = GetDlgItem(hDlg,IDC_RES); hBuf[0] = GetDlgItem(hDlg,IDC_BUF1); hBuf[1]= GetDlgItem(hDlg,IDC_BUF2); hTxt[0] = GetDlgItem(hDlg,IDC_ZG); hTxt[1] = GetDlgItem(hDlg,IDC_WST); hTxt[2] = GetDlgItem(hDlg,IDC_GJJ); hTxt[3] = GetDlgItem(hDlg,IDC_DD); //初始化文本框 ::SetWindowText(hRes, TEXT("0")); ::SetWindowText(hBuf[0], TEXT("0")); ::SetWindowText(hBuf[1], TEXT("0")); break; } case WM_COMMAND: switch (LOWORD (wParam)) { case IDC_BTN: { ::CreateThread(NULL, 0, ThreadBegin,NULL, 0, NULL); return TRUE; } } break ; } return bRet; } //入口函数 int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { DialogBox(hInstance,MAKEINTRESOURCE(IDD_MAIN),NULL,MainDlgProc); return 0; }

浙公网安备 33010602011771号