「SDL第六篇」孙悟空与多线程

前言

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

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

  • SDL 入门
  • SDL窗口渲染
  • SDL基本图形绘制
  • SDL事件处事
  • 彻底理解SDL纹理

另外,我在慕课网分享了音视频免费入门课程,有兴趣的同学可以去观看。

为啥要用多线程?

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

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

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

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

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

线程互斥与同步

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

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

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

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

锁的种类

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

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

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

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

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

死锁问题

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

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

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

SDL多线程

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

  • 创建线程

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

    void SDL_WaitThread(SDL_Thread* thread,
                      int*        status)
    

    等待线程结束。

  • 创建互斥量

    SDL_mutex* SDL_CreateMutex(void)
    

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

  • 销毁互斥量

    void SDL_DestroyMutex(SDL_mutex* mutex)
    
  • 加锁

    int SDL_LockMutex(SDL_mutex* mutex)
    
  • 解锁

    int SDL_UnlockMutex(SDL_mutex* mutex)
    

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

例子

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

#include 
#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 中的多线程。

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

隆重推荐

我的免费音视频入门课

你可能感兴趣的:(「SDL第六篇」孙悟空与多线程)