C++学习日志之二—贪吃蛇网游化框架搭建5多线程同步

来源:互联网 发布:百度云主机绑定域名 编辑:程序博客网 时间:2024/05/17 00:05

  从前面介绍的GAME类主体实现函数可以看出,整个游戏过程处于一个无限循环的过程中,为了保证游戏数据实时保存在服务端,在每一轮循环中都需要将更新的数据进行发送,这里本来可以直接在playgame函数体最后加上senddata函数实现这个功能,但为了学习应用下多线程技术,同时也可以将游戏进行过程中的通信部分与游戏部分分离开,以防止互相干扰,提高效率,因此新创建了一个线程专门用于发送游戏数据到服务端,定义线程函数:
  

HANDLE hSemaphore,h_event1,h_event2;DWORD dwThreadId;HANDLE hThread;DWORD WINAPI ThreadFunc(LPVOID lpParam){    DWORD waitresult;    Game* temp = (Game*)lpParam;    while (1) {        if ((waitresult = WaitForSingleObject(hSemaphore, 0))==WAIT_OBJECT_0)            break;        WaitForSingleObject(h_event2, INFINITE);        ResetEvent(h_event2);        temp->senddata();        SetEvent(h_event1);    }    return 0;}

  在游戏main函数中加入如下代码:

    h_event1 = CreateEvent(NULL, true, false, nullptr);    h_event2 = CreateEvent(NULL, true, false, nullptr);    hSemaphore = CreateSemaphore(NULL, 0, 1, NULL);//创建信号    hThread = CreateThread(NULL, 0, ThreadFunc, (void*)&mygame, 0, &dwThreadId);

  plyagame函数首端加入以下前两行代码,sleep前加入最后一行代码:

WaitForSingleObject(h_event1, INFINITE);ResetEvent(h_event1);SetEvent(h_event2);

  在最初的多线程实现中,并未加入关于事件的代码,导致游戏运行过程中不时会报错,主要时由于多线程不同步的问题导致的,主线程部分会不断的改变snake类和相关类的数据,而senddata函数则需要读取相应的数据,如果在读取过程中,恰好主线程将相应数据进行了删除,则将出现读取不到数据的错误,因此之后加入了多线程同步的相关代码;
  多线程同步的实现方法有很多,这里主要采用了创建两个事件的方式进行,通信的线程在运行时,会等待主线程将event2激活,而主线程在运行到sleep之前时会激活event2,这样在主线程挂起时通信线程完成发送数据的操作,在通信良好的情况下,通信线程在主线程挂起期间完成发送数据并激活event1,这样主线程在进入下一轮循环时,接受到event1被激活的信号从而继续运行下面的代码,而若网络不好,则主线程会陷入停滞,这里还可以设置主线程等待事件,若等待时间过长则转入与用户相互的代码,这部分代码比较容易也就没有再写了。
  同时另外定义了一个semaphore,当游戏结束时该信号被激活,通知通信线程游戏已结束,并跳出循环。
  函数的最后就是关闭各类句柄的代码了:
  

if (!mygame.playagain()) {            SetEvent(h_event2);            ReleaseSemaphore(hSemaphore, 1, NULL);            CloseHandle(hSemaphore);            CloseHandle(hThread);            CloseHandle(h_event1);            CloseHandle(h_event2);            break;        }

  至此,贪吃蛇网游化框架的主体搭建就全部完成了,整个框架还存在很多的不足,例如异常处理代码几乎全部被忽略,但出于只是复习所学知识的目的就不多做重复性工作了,下面贴几张游戏运行过程图:
  这里写图片描述
  这里写图片描述
  这里写图片描述
  这里写图片描述