随笔 - 96  文章 - 255  trackbacks - 0
<2015年7月>
2829301234
567891011
12131415161718
19202122232425
2627282930311
2345678

E-mail:zbln426@163.com QQ:85132383 长期寻找对战略游戏感兴趣的合作伙伴。

常用链接

留言簿(21)

随笔分类

随笔档案

SDL相关网站

我的个人网页

我的小游戏

资源下载

搜索

  •  

积分与排名

  • 积分 - 486575
  • 排名 - 37

最新评论

阅读排行榜

评论排行榜

作者:龙飞

2.1:竞争条件(Race Conditions)

        我们在前面将一个普通函数调用转换成了用线程调用,这意味着我们可以“同时”调用两个以上的线程。例如,我们希望在屏幕的另外一个位置也播放这段简单的动画,我们只需要添加一个线程的调用就可以了。
int main(int argc ,char* argv[])
{
    
//Create a SDL screen.
    const int SCREEN_WIDTH = 640;
    
const int SCREEN_HEIGHT = 480;
    
const Uint32 SCREEN_FLAGS = 0//SDL_FULLSCREEN | SDL_DOUBLEBUF | SDL_HWSURFACE
    const std::string WINDOW_NAME = "Amn Test";
    ScreenSurface screen(SCREEN_WIDTH, SCREEN_HEIGHT, WINDOW_NAME, 
0, SCREEN_FLAGS);

    PictureSurface bg(
"./images/background.png", screen);
    bg.blit(
0);
    screen.flip();

    AmnArg test1(
0250600250, screen);
    SDL_Thread
* thread1 = SDL_CreateThread(amn, (void*)&test1);

    AmnArg test2(
006000, screen);
    SDL_Thread
* thread2 = SDL_CreateThread(amn, (void*)&test2);

    SDL_Event gameEvent;
    
bool gameOver = false;
    
while ( gameOver == false ){
        
while ( SDL_PollEvent(&gameEvent) != 0 ){
            
if ( gameEvent.type == SDL_QUIT ){
                gameOver 
= true;
            }
            
if ( gameEvent.type == SDL_KEYDOWN ){
                
if ( gameEvent.key.keysym.sym == SDLK_ESCAPE ){
                    gameOver 
= true;
                }
            }
            screen.flip();
        }
    }

    SDL_KillThread(thread1);
    SDL_KillThread(thread2);
    
return 0;
}
这段程序看起来似乎没有什么问题,但是运行的时候,不可预知的情况出现了:理论上我们几乎同时调用了两个线程,动画似乎应该是同步播放的,但是实际上,两段动画的播放并不同步,并且每次执行的效果都不一样——有时候上面的图片移动快,有时候下面的图片移动快,并且速度不均匀。
        这就是典型的race conditions的表现。还记得我说过没有定义dt吗,我们让电脑以其所能达到的最快速度决定dt,换句话说,我们每一个线程都试图“咬死”CPU的运算,当然,在实际中多任务的OS会帮助CPU分配任务,但是如何分配却是不确定的,因为OS并不知道哪些任务需要优先执行,所以,两个线程实际上在竞争电脑的性能资源,产生的结果就是不确定的。

2.2:松开“死咬”的CPU
void SDL_Delay(Uint32 ms);
        解决race conditions的方法就是给CPU足够的时间“休息”,而这正好也是我们自己定义dt所需要的。SDL_Delay()在这个时候就显得意义重大了。当今电脑的运算速度非常非常快,以至于哪怕我们仅仅给电脑0.01秒的时间“休息”(每次循环中),电脑都会显得很轻松了。
int amn(void* data)
{
    AmnArg
* pData = (AmnArg*)data;
    PictureSurface stand(
"./images/am01.png", pData->screen);
    stand.colorKey();
    PictureSurface bg(
"./images/background.png", pData->screen);

    
const int SPEED_CTRL = 300;
    
int speedX = (pData->endX - pData->beginX) / SPEED_CTRL;
    
int speedY = (pData->endY - pData->beginY) / SPEED_CTRL;

    
for ( int i = 0; i < SPEED_CTRL; i++ ){
        pData
->beginX += speedX;
        pData
->beginY += speedY;
        bg.blit(pData
->beginX, pData->beginY, pData->beginX, pData->beginY, stand.point()->w, stand.point()->h, 22);
        stand.blit(pData
->beginX, pData->beginY);
        pData
->screen.flip();
        SDL_Delay(
10);
    }

    
return 0;
}
说到这里,我们不得不提及之前一直所忽略的一个问题:我们之前凡是涉及循环等待事件轮询的程序总是占用100%的CPU,这并不是因为我们真正用到了100%的CPU性能,而是我们让CPU陷入了“空等”(Busy Waiting)的尴尬境地。轮询事件得到响应相对于循环等待来说,是发生得非常缓慢的事情,我们在循环中,哪怕是让电脑休息0.01秒,事情都会发生本质性的改变:
    while ( gameOver == false ){
        
while ( SDL_PollEvent(&gameEvent) != 0 ){
            
if ( gameEvent.type == SDL_QUIT ){
                gameOver 
= true;
            }
            
if ( gameEvent.type == SDL_KEYDOWN ){
                
if ( gameEvent.key.keysym.sym == SDLK_ESCAPE ){
                    gameOver 
= true;
                }
            }
            screen.flip();
        }
        SDL_Delay(
10);
    }
当我们重新运行新程序的时候,我们可以看到程序对CPU的占用从100%骤降到了0%!这当然并不意味着程序就用不上CPU了,而是说,这些运算对于我们的CPU来说,实在是小菜一碟了,或者从数据上说,处理这些运算的时间与0.01秒来比较,都几乎可以忽略不计!

2.3:GUI线程与worker线程

        我们的另外一项试验是将事件轮询放到动画线程中,程序就不多写了,大家可以自己试下。我直接说结论:动画线程中无法响应事件轮询。
        一般提倡的模式,是将GUI事件都写在主线程中,而将纯粹的运算才写到由主线程创建的线程中,后者也就是所谓的worker线程。从另外一个概念看,只有主线程控制着“当前窗口”,其它线程也许在后台,也许虽然也是在前台但是并非是我们可见的,所以,轮询事件找不到接口。
        对于抛出的线程与主线程之间的通讯,我们可以通过他们共享的数据来进行控制,所以,尽管事件轮询不能直接影响worker线程,但是我们仍然是可以通过主线程进行间接影响的。
posted on 2008-04-28 12:47 lf426 阅读(6731) 评论(0)  编辑 收藏 引用 所属分类: SDL入门教程

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理