C++多核多线程同步实现

使用Makefile C++11工程模拟dsp的多核同步逻辑,使用多线程模拟多核,多个线程通过C++11的条件变量实现同步。
当某一线程执行到同步函数syn_func时,判断是否其他线程执行到此处了,若有其他线程没有执行到此处,本线程就应阻塞。
当最后一个线程执行到同步函数时,通知所有线程解除阻塞,实现同步。
为了实现这个过程,首先需要一个条件变量,阻塞各线程。其次,需要一个全局变量,作为各线程运行到位的依据。所以一个简单的实现:
 1 mutex dsp_lock;
 2 condition_variable dsp_cva; //条件变量
 3 vu32 dsp_cva_no=0; //多核同步的数量
 4 
 5 void syn_func() //多核同步
 6 {
 7     unique_lock<mutex> lk(dsp_lock);
 8     dsp_cva_no++;
 9     if(dsp_cva_no>=NCORES) //若自己是最后一个
10     {
11         dsp_cva_no=0;
12         dsp_cva.notify_all();
13     }
14     else dsp_cva.wait(lk); //若不是,就等,单独的wait可能造成虚假唤醒
15 }
这个实现逻辑非常简单,但条件变量的wait函数可能造成虚假唤醒,导致失步。所以必须使用带条件的wait函数来实现。
条件变量的wait函数在带锁的条件下执行条件函数,确定是否需要等待,若需要等待,就解除互斥锁,并阻塞线程。
由于解除阻塞时多了一个 加锁-判断-解锁 的过程,先完成的线程会立刻执行同步点之后的程序,可能会修改同步变量,从而导致后执行的线程判断错误。
所以需要修改同步变量的机制,改为记录每个核的同步序号,每次同步时序号加1。为处理序号溢出问题,判断时,判断本线程序号是否等于其他线程的序号减1,从而得出其他线程是否已经进入下一个同步点的结论。
 1 mutex dsp_lock;
 2 condition_variable dsp_cva; //条件变量
 3 vu32 dsp_cva_no[NCORES]={0}; //每一个核1个序号
 4 
 5 void syn_func() //多核同步
 6 {
 7     unique_lock<mutex> lk(dsp_lock);
 8     int cn=coreNum;
 9     dsp_cva_no[cn]++;
10     dsp_cva.wait(lk,[cn]()
11     {
12         for(int i=0;i<NCORES;i++)
13         {
14             if(dsp_cva_no[cn]!=dsp_cva_no[i] && //若有不同步的
15                 dsp_cva_no[cn]!=(dsp_cva_no[i]-1)) //或其它核已经进入下个了
16             {
17                 return 0; //未同步,有的核没跟上
18             }
19         }
20         return 1;
21     });
22     dsp_cva.notify_all();
23 }
程序中,调用同步函数直接就调用wait函数,通过条件函数判断是否需要阻塞。阻塞的标准是各线程步骤序号不同。最后一个同步的线程不经阻塞,直接调用notify_all,通知所有线程开始执行。即使第一个线程已经执行到下一个同步点,修改了同步变量,其他线程判断同步变量时,也能判断出自己是落后的,从而解除阻塞。
所有线程解除阻塞时,都会调用notify_all函数,但不会对同步造成影响,因为线程阻塞时会判断同步变量才解除阻塞。
posted on 2023-04-08 21:27  yangzifb  阅读(221)  评论(0编辑  收藏  举报