美文网首页
c语言实现多线程并发

c语言实现多线程并发

作者: 梁帆 | 来源:发表于2021-06-28 16:20 被阅读0次

    首先,c语言的多线程并发,需要用到 pthread.h 库。

    #include <pthread.h>

    1、开启一个线程

    下面代码是最基本的多线程实现:

    主要分为三步:

    1、声明一个线程变量th,类型为pthread_t;

    2、使用pthread_create函数进行创建,第一个参数是线程变量的地址,第三个参数是线程执行的函数(返回值为void*);

    3、pthread_join函数等待;

    编译的时候要注意,涉及到多线程的时候,得在gcc参数里加上 -lpthread:

    可以发现,成功输出了hello world。

    2、开启两个线程

    当我们开启两个线程,代码如下:

    执行的任务都是打印1~499的时候可以发现:

    输出的时候,两个线程是错序的。

    再对代码做以下修改:

    这里我们用到了pthread_create函数的第4个参数,这个参数的传入会反应到myfunc中的形参中去。最后输出的结果,我们可以清晰地看出th1和th2的线程标记和交错运行:

    这里th2输出数字58的时候,th1才开始输出数字1。

    3、多线程进行协同运算

    我们创建一个数组,其中有5000个元素,我们想用两个线程来共同计算这5000个元素的加法和。

    从两个线程的函数可以看出,一个线程计算前2500个值的加法和,另一个线程计算后2500个值的加法和。

    main函数中,在pthread_join函数等待的th1和th2都结束后,输出对应的值。

    编译运行后:

    代码改进:

    可以看到我们的代码里,th1和th2的执行函数中有大量的相似代码,所以我们最后用一个函数来复用,不难想到,需要通过传参的方式来实现代码复用。这里我们定义了一个结构体,结构体中有循环的起始标记first,终止标记last,区间内加法和result。

    从上图可以看出,我们把myfunc1和myfun2整合到了myfunc中去。而在main函数中,我们创建线程的时候传入的参数正是结构体指针:

    这样在myfunc函数中,我们就可以对传入的结构体参数中的元素进行利用了,将计算所得传到结构体的result中去。这样我们输出加法和,就可以得到跟上面一样的结果,但是代码会更整洁漂亮:

    4、并发程序引起的共享内存问题

    有如下代码。有两个进程,两个进程共享全局变量s。两个进程都执行一个计数功能的函数,直观地看过去,th1运行时s++要执行10000次,th2运行时s++也要执行10000次,似乎计算得到的最后s应该是20000。但实际上是这样的吗?

    编译运行后,发现输出如下:

    s并不是20000,而是12657。

    原因其实很简单:

    当我们执行s++,底层发生的事件其实是:内存中读取s→将s+1→将s写入到内存。这不是一个原子化操作,当两个线程交错运行的时候,很容易发生结果的丢失。因此最后的结果肯定是要小于20000的。这种情况有种专有名词,叫race condition。

    为了解决这个问题,我们可以加锁

    改进后的代码如下,学过操作系统会很好理解,无非就是为了保证共享内存区(临界区)的原子化操作,我们可以在进这段代码之前加锁(pthread_mutex_lock),意味着其他线程看到这段内存被其他人占有的时候,就不去抢占,等这段内存被解锁(pthread_mutex_unlock)之后,它才有读写这段临界区的权利。

    但其实这种方式的执行速度并不快,比如这段代码里,每个线程都要进行10000次加解锁的操作,它能解决内存读写冲突的问题,但是却牺牲了效率。

    相关文章

      网友评论

          本文标题:c语言实现多线程并发

          本文链接:https://www.haomeiwen.com/subject/fxpqultx.html