0%

SDL多线程

今天将向大家介绍一下SDL中的多线程的使用。通过下面对SDL 线程与锁相关的API介绍,你会发现,它与 Linux, Windows相关的API几乎是一模一样的。从这里可以推断出,其实SDL对于多线程的处理只是为大家提供了一套统一接口,并没有做其它太多的工作。

这是我们介绍 SDL 的第六篇文章。有兴趣的同学可以通过下面的链接查看其它几篇文章。

为啥要用多线程?

我觉得这个小节的标题就是一个废话。不过为了文章的完整性,还是简单的说一说吧。多线程(多进程)是啥意思呢?做个不恰当的比喻,可以把CPU看成是孙悟空,它有一个能耐,从后脑揪几个猴毛就可以变出许多的小猴子。

多线程(多进程)就是这些小猴子。当干一件比较复杂的事儿时,可以孙悟空一个人干,这样自己比较累。它还有一种选择就是揪几根猴毛,让小猴子们一起帮着干。这样一件复杂的事件,分给许多猴子干,每只猴只干一部分,事情很快就被做完了,这样岂不是比一个人干要强的多?

当然,有好处也有坏外。猴子多了就需要管理,如果管理不好,就会闹翻天。比如,只有一块肉,该给哪个猴子吃呢?这真是一个另人头痛的问题。

实际上整个操作系统的演进,就是一部管理学的演进。如何才能让CPU,内存,磁盘I/O,各种设备之间高效的工作,一直是操作系统追求的目标。当然,这话有点扯远了。

今天我们要讲的就是多线程(多进程)之间该如何高效的工作。要想让多线程之间高效工作,就要给它们之间立点规矩,大家都要遵守的规矩。

线程互斥与同步

当僧多粥少时,就引入了互斥的概念。再举个我们生活中的例子吧,比如有一大家族住在同一个大屋子里,却只有一个厕所。早上起来大家都想去厕所,这时有谁先抢到了厕所,其它人就只能等他出来后再进入了,这就是互斥

当仅有一份资源,大家都需要时,这就产生了管理问题。解决的办法就是通过互斥方法来解决。这种情况是在做多线程处理时要尽量避免的;如果资源足够呢?那当然是平均分配,人人有份了。这中情况是多线路程最希望的。

除了互斥之外,有些情况还需要更精细化的管理,比如说同步。例如车间里的流水线,每个人负责一块,每一块都是半成品,第一个人完成之后交给第二个人做下一步,而后面的人又必须依赖于前而人的结果,依次类推,最后一个人才能完成最终的产品。这就是线程间的精细化管理同步

要想实现互斥和同步,就需要一种机制。在操作系统上提供了锁的概念来达到互斥与同步。

锁的种类

在操作系统上有很种锁,有读写锁、自旋锁、可重入锁等。下面我简单的介绍一下它们之间的不同。

读写锁: 分为读锁与写锁。所谓读锁就是被访问的资源只要你不改变它的值,你就可以访问,但如果你想改变它,那么就需要等所有读它的线程都释放了它们的锁后,才可以进行修改;写锁是同一时刻只能有一个人访问,当资源被加锁后,其它人只能等待。

自旋锁: 偿试着给访问资源加锁,如果此时被访问资源已经上锁了,那就一直不停的偿试,直到加锁成功为止。由于它会非常消耗CPU资源,所以一般只锁今资源非常短的情况下才能使用它。

可重入锁: 同一个线程对被访问资源可以一直加锁。但如果被访问资源已经上锁了,那么其它线程则无法对其加锁。

锁是解决互斥的一种好办法,但同样有利必有弊。如果使用不善就会出现死锁。

死锁问题

死锁顾名思意,就是打不开的锁。它是怎么产生的呢?举个例子,两个人需要一起完成一件事儿,A说他要等B做完了,他才能开始;而B说它要等A做完了,它才能开使。于时他们在相互等待中老去。

看类很简单的问题,但这类事情经常在我们的工作中出现。而在我们开发的多线程程序中更是频繁出现。别说人没遇到过哟!

如何解决?那就是考验你的管理能力了。共实很多情况是出现了死锁我们自己却不知道,否则的话,凭我们的聪名才智怎么能让他们一直锁在那儿呢。

SDL多线程

上面介绍了一大堆的理论,现在来看看 SDL 为我们都提供了那些API吧。

  • 创建线程

    1
    2
    3
    SDL_Thread* SDL_CreateThread(SDL_ThreadFunction fn,
    const char* name,
    void* data)
    • fn: 线程要运行的函数。
    • name: 线程名。
    • data: 函数参数。
  • 等待线程

    1
    2
    void SDL_WaitThread(SDL_Thread* thread,
    int* status)

    等待线程结束。

  • 创建互斥量

    1
    SDL_mutex* SDL_CreateMutex(void)

    也就是创建一个稀有资源,这样大家就去抢这个资源。从而达到为真正资源加锁的目的。

  • 销毁互斥量

    1
    void SDL_DestroyMutex(SDL_mutex* mutex)
  • 加锁

    1
    int SDL_LockMutex(SDL_mutex* mutex)
  • 解锁

    1
    int SDL_UnlockMutex(SDL_mutex* mutex)

常用的与线程和锁相关的 API 就以上几个,是不是非常简单?下面我们来看一个简单的例子吧。

例子

下面这个例子是在主线程中创建了一个子线程。然后主线程就一直等待子线程结束。等子线程结束后,主线程也随之结束。

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
#include <stdio.h>
#include "SDL.h"

/* Very simple thread - counts 0 to 9 delaying 50ms between increments */
static int TestThread(void *ptr)
{
int cnt;

for (cnt = 0; cnt < 10; ++cnt) {
printf("\nThread counter: %d", cnt);
SDL_Delay(50);
}

return cnt;
}

int main(int argc, char *argv[])
{
SDL_Thread *thread;
int threadReturnValue;

printf("\nSimple SDL_CreateThread test:");

/* Simply create a thread */
thread = SDL_CreateThread(TestThread, "TestThread", (void *)NULL);

if (NULL == thread) {
printf("\nSDL_CreateThread failed: %s\n", SDL_GetError());
} else {
SDL_WaitThread(thread, &threadReturnValue);
printf("\nThread returned value: %d", threadReturnValue);
}

return 0;
}

小结

本文主要介绍了两方面的内容。一是对多线程理论做了一下简单的介绍;二是介绍了SDL中与线程和锁相关的API。

最后通过一个例子显示了如何使用 SDL 中的多线程。

希望本文能对你有所帮助,谢谢!

隆重推荐

欢迎关注我的其它发布渠道