十一 22
Near其他技术 iOS, iPhone, SDL, Uint32, Uint8
转自己的两条微薄:
1. 搞嵌入式的人之所以有乐趣,就是因为需要程序员专注每一个字节,甚至每一个bite,如何用最少的空间和最快的时间完成一件事情;搞嵌入式的人之所以不开心,因为哪怕是错了一个字节,甚至是一个byte,都会及其抓狂调试查处问题的根源所在。虽然我不搞嵌入式,但是深深地体验了一把从后者到前者的过程。
2. 抓狂了我一整个周末时间的问题在这个时刻终于被搞定,原因就是SDL的EventType从原来的Uint8(unsigned char)提升到了Uint32(unsigned int), 所以很多参数传入之前的程序就会导致直接被截断,导致各种离谱的现象发生。所以提醒各位,在升级第三方 library的时候一定要看API Changes文档,不然自找苦吃。
------------------------------
最近继续搞视频播放器,从许久没有动过的毕设项目抓过来用。但是我还是很手贱地升级了一下其中的一个第三方库SDL。为什么说手贱,因为“不要什么都追求时髦,不要什么都追求最新版本,一定要本着够用万岁的心态,这样才能把事情做得更好。” 但是我还是升级了SDL库。于是悲剧就发生了。各种时间回调不出来,图像decode不出来,声音播放不出来,整整让人绝望了一个周末。。。所以这几天笔者十分焦躁,心理波动较大,如果做出了什么合适的事情上伤害到了某些人,谅解,我也不想这样。
在百般无奈之下只好怀疑是新版本的SDL不稳定,有bug。于是狂搜论坛,看帖子,发帖子,甚至直接给开发者写信过去,尽管现在都没有任何人鸟我。。。最后只要自己不得不看源代码了,并不断对比老版本的源代码。。。及其痛苦。。。而且还在多线程中间用printf之类的调试,一遍又一遍。。。最后终于发现了问题所在,就在这个时刻的前一个小时。
问题很简单其实,低版本的SDL因为event事件不多,所以eventType就用了Uint8表示,但是随着库的开发越来越多的事件加入了,开发者可能担心不够用了,于是把这个改成了Uint32。而这个时候我自己的程序还傻逼的停留在Uint8,所以穿进来的很多参数都溢出了,程序很自然地出错了。。。于是改之,程序活甭乱跳。
只能说,一直都在做应用层开发的人,突然跑到嵌入式的领域,浑然已经忘记了如何去照顾好每一个字节。而且在使用新lib的时候,看开发团队的api changs文档至关重要!
十一 16
Near其他技术 NSRunloop, NSTimer, SDL, timer, 精确, 计时器
有点标题党,最近在看开源游戏库SDL(http://www.libsdl.org/),只是因为要用到其中的thread和timer这些东西,所以就顺便看了看源代码,发现timer很精悍,所以分享其中的带代码。
1. 首先通过init函数创建一个timer自己的thread(暂且叫timer线程),所以在使用timer之前一点要先调用init函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| int
SDL_SYS_TimerInit(void)
{
timer_alive = 1;
timer = SDL_CreateThread(RunTimer, NULL);
if (timer == NULL)
return (-1);
return (SDL_SetTimerThreaded(1));
}
static int
RunTimer(void *unused)
{
while (timer_alive) {
if (SDL_timer_running) {
SDL_ThreadedTimerCheck();
}
SDL_Delay(1);
}
return (0);
} |
2. 添加一个timer, 新建一个维护timer信息的内部struct,并讲这个struct添加到维护有所有在running的timer链表中去。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| static SDL_TimerID
SDL_AddTimerInternal(Uint32 interval, SDL_NewTimerCallback callback,
void *param)
{
SDL_TimerID t;
t = (SDL_TimerID) SDL_malloc(sizeof(struct _SDL_TimerID));
if (t) {
t->interval = ROUND_RESOLUTION(interval);
t->cb = callback;
t->param = param;
t->last_alarm = SDL_GetTicks();
t->next = SDL_timers;
SDL_timers = t;
++SDL_timer_running;
list_changed = SDL_TRUE;
}
#ifdef DEBUG_TIMERS
printf("SDL_AddTimer(%d) = %08x num_timers = %d\n", interval, (Uint32) t,
SDL_timer_running);
#endif
return t;
} |
2. timer线程的唯一工作就是不断地去更新timer的ticks,当发现timer的ticks满足interval的时候就触发timer并讲这个timer从链表中移出。
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
| void
SDL_ThreadedTimerCheck(void)
{
Uint32 now, ms;
SDL_TimerID t, prev, next;
SDL_bool removed;
SDL_mutexP(SDL_timer_mutex);
list_changed = SDL_FALSE;
now = SDL_GetTicks();
for (prev = NULL, t = SDL_timers; t; t = next) {
removed = SDL_FALSE;
ms = t->interval - SDL_TIMESLICE;
next = t->next;
if ((int) (now - t->last_alarm) > (int) ms) {
struct _SDL_TimerID timer;
if ((now - t->last_alarm) < t->interval) {
t->last_alarm += t->interval;
} else {
t->last_alarm = now;
}
#ifdef DEBUG_TIMERS
printf("Executing timer %p (thread = %lu)\n", t, SDL_ThreadID());
#endif
timer = *t;
SDL_mutexV(SDL_timer_mutex);
ms = timer.cb(timer.interval, timer.param);
SDL_mutexP(SDL_timer_mutex);
if (list_changed) {
/* Abort, list of timers modified */
/* FIXME: what if ms was changed? */
break;
}
if (ms != t->interval) {
if (ms) {
t->interval = ROUND_RESOLUTION(ms);
} else {
/* Remove timer from the list */
#ifdef DEBUG_TIMERS
printf("SDL: Removing timer %p\n", t);
#endif
if (prev) {
prev->next = next;
} else {
SDL_timers = next;
}
SDL_free(t);
--SDL_timer_running;
removed = SDL_TRUE;
}
}
}
/* Don't update prev if the timer has disappeared */
if (!removed) {
prev = t;
}
}
SDL_mutexV(SDL_timer_mutex);
} |
这个过程也阐述了timer的基本工作原理,所以也证明了timer不能用来作为精确控制,而且在SDL里面timer只能最多精确到10ms。
并且联系这个过程可以联想到Cocoa中的NSTimer,其实NSTimer也是这样被添加到NSRunloop中,然后到时间后就触发。
近期评论