C++11多线程与信号量

目录

最终目标:

纯线程无信号量

打印结果:

加入信号量同步

输出:

CMakeLists.txt

编译运行


最终目标:

1. c++类,创建3个线程,基类每隔1秒钟生产一个信号量,2个子类,消费信号量,达到同步效果

2. 以成员函数为线程

3. 基类创建线程,子类继承创建方法,重写线程函数

4. 3个线程修改全局变量g_nCount

纯线程无信号量

#include <string>
#include <iostream>
#include <thread>

int g_nCount = 0;
class CBaseWorker
{
public:
    CBaseWorker(){}
    virtual ~CBaseWorker(){}

    void startJob()
    {
        m_bRunning = true;
        std::thread t(&CBaseWorker::ThreadFunc, this);
        //t.join();
        t.detach();
    }
private:
    virtual void ThreadFunc()
    {
        while(m_bRunning)
        {
           std::cout<<std::endl;
           std::cout<<"line:"<<__LINE__<<"  CBaseWorker...m_nCount="<<++g_nCount<<std::endl;
           std::this_thread::sleep_for(std::chrono::seconds(1));
        }
    }
protected:
    bool m_bRunning=false;
};

class CAWorker:public CBaseWorker
{
private:
    virtual void ThreadFunc() override
    {
        while(m_bRunning)
        {
           std::cout<<"line:"<<__LINE__<<"  A Worker...m_nCount="<<++g_nCount<<std::endl;
           std::this_thread::sleep_for(std::chrono::seconds(1));
        }
    }
};

class CBWorker:public CBaseWorker
{
private:
    virtual void ThreadFunc() override
    {
        while(m_bRunning)
        {
           std::cout<<"line:"<<__LINE__<<" B Worker...m_nCount="<<++g_nCount<<std::endl;
           std::this_thread::sleep_for(std::chrono::seconds(1));
        }
    }
};

int main()
{
    CBaseWorker base_worker;
    base_worker.startJob();
    CAWorker a_worker;
    CBWorker b_worker;
    a_worker.startJob();
    b_worker.startJob();
    getchar();
    std::cout<<"**************  exit()  *****************"<<std::endl;
    return 0;
}

打印结果:


deMacBook-Pro demo % ./demo 

line:25  CBaseWorker...m_nCount=1
line:53 B Worker...m_nCount=2
line:40  A Worker...m_nCount=3

line:line:40  A Worker...m_nCount=4
25  CBaseWorker...m_nCount=5
line:53 B Worker...m_nCount=6
line:
line:25  CBaseWorker...m_nCount=7
40  A Worker...m_nCount=line:538
 B Worker...m_nCount=9

line:53 B Worker...m_nCount=10
line:40  A Worker...m_nCount=line:11
25  CBaseWorker...m_nCount=12
line:53 B Worker...m_nCount=13
line:40  A Worker...m_nCount=14

line:25  CBaseWorker...m_nCount=15
line:
line:25  CBaseWorker...m_nCount=16
53 B Worker...m_nCount=17
line:40  A Worker...m_nCount=18

line:25  CBaseWorker...m_nCount=19
line:53 B Worker...m_nCount=20
line:40  A Worker...m_nCount=21

line:25  CBaseWorker...m_nCount=22
line:40  A Worker...m_nCount=23
line:53 B Worker...m_nCount=24

line:line:25  CBaseWorker...m_nCount=25
line:53 B Worker...m_nCount=4026
  A Worker...m_nCount=27

**************  exit()  *****************
deMacBook-Pro demo % 

可以看出来,打印相当的混乱。

加入信号量同步

#include <string>
#include <iostream>
#include <thread>
#include <semaphore.h>
#include <fcntl.h>

int g_nCount = 0;
sem_t *g_pSem = nullptr; //信号量
class CBaseWorker
{
public:
    CBaseWorker(){
    }
    virtual ~CBaseWorker(){
    }

    //启动线程
    void startJob()
    {
        m_bRunning = true;
        std::thread t(&CBaseWorker::ThreadFunc, this);
        //t.join();
        t.detach();
    }

    //停止线程
    void stopJob()
    {
        m_bRunning = false;

        // printSem(__LINE__);
        // //macos下,一个生产者+多个消费者,结束任务时,需要sem_post,否则会出现sem_close阻塞的情况,原因不明;linux正常;
        // while(sem_trywait(g_pSem))
        // {
        //     printSem(__LINE__);
        //     std::cout<<"line:"<<__LINE__<<"  will stop sem..."<<std::endl;
        //     sem_post(g_pSem);
        // }
    }

    //打印信号量的状态
    void printSem(int lineNum)
    {
        int nSemValue=-1;
        int ret = sem_getvalue(g_pSem, &nSemValue);
        if(ret < 0)
        {
             std::cout<<"line:"<<lineNum<<" >>>> sem_getvalue error... ret="<<ret<<std::endl;
        }else{
            std::cout<<"line:"<<lineNum<<" >>>> sem_getvalue nSemValue="<<nSemValue<<std::endl;
        }
    }
private:
    virtual void ThreadFunc()
    {
        while(m_bRunning)
        {
            std::cout<<std::endl;
            std::cout<<"line:"<<__LINE__<<"  send sem..."<<std::endl;
            //每1秒钟发送一个信号量
            sem_post(g_pSem);//信号量加一
            printSem(__LINE__);
            std::this_thread::sleep_for(std::chrono::seconds(1));
        }
    }
protected:
    bool m_bRunning=false;
};

class CAWorker:public CBaseWorker
{
private:
    virtual void ThreadFunc() override
    {
        while(m_bRunning)
        {
            printSem(__LINE__);
            //阻塞,等待信号量
            sem_wait(g_pSem);//信号量减一
            printSem(__LINE__);
            std::cout<<"line:"<<__LINE__<<"  A Worker...m_nCount="<<++g_nCount<<std::endl;
            //std::this_thread::sleep_for(std::chrono::seconds(1));
        }

        std::cout<<"line:"<<__LINE__<<"  A Worker...exit"<<std::endl;
    }
};

class CBWorker:public CBaseWorker
{
private:
    virtual void ThreadFunc() override
    {
        while(m_bRunning)
        {
            printSem(__LINE__);
            //阻塞,等待信号量,do something
            sem_wait(g_pSem);//信号量减一
            printSem(__LINE__);
            std::cout<<"line:"<<__LINE__<<" B Worker...m_nCount="<<++g_nCount<<std::endl;
        }
        std::cout<<"line:"<<__LINE__<<"  B Worker...exit"<<std::endl;
    }
};

int main()
{
    //第1个参数:会生成一个文件/dev/shm/sem.mysem,进程结束后,会自动删除
    //第3个参数,信号量的初始化值
    g_pSem = sem_open("mysem",O_CREAT, S_IRUSR | S_IWUSR, 0);
    if(nullptr==g_pSem)
    {
        //macos不支持无名信号量,坑,有名信号量总是可以在不同进程间共享的
        //linux下可以用sem_init/sem_destroy无名(内存)信号量
        std::cout<<"sem_open g_pSem="<<g_pSem<<std::endl;
        return -1;
    }

    std::cout<<"sem_open success."<<std::endl;
    CBaseWorker base_worker;
    CAWorker a_worker;
    CBWorker b_worker;
    //base_worker 每隔一秒产生一个信号量
    //a_worker 消费信号量
    //b_worker 消费信号量
    base_worker.startJob();
    a_worker.startJob();
    b_worker.startJob();

    getchar();

    std::cout<<"**************  exit()  *****************"<<std::endl;

    //停止线程和信号量
    //base_worker.stopJob();
    //a_worker.stopJob();
    //b_worker.stopJob();

    base_worker.printSem(__LINE__);
    sem_close(g_pSem);
    std::cout<<"************** sem_close  *****************"<<std::endl;
    sem_unlink("mysem");
    std::cout<<"**************  sem_unlink  *****************"<<std::endl;
    return 0;
}

输出:

[root@VM-20-16-centos demo]# ./demo 
sem_open success.

line:59  send sem...
line:62 >>>> sem_getvalue nSemValue=1
line:77 >>>> sem_getvalue nSemValue=1
line:80 >>>> sem_getvalue nSemValue=0
line:81  A Worker...m_nCount=1
line:77 >>>> sem_getvalue nSemValue=0
line:96 >>>> sem_getvalue nSemValue=0

line:59  send sem...
line:62 >>>> sem_getvalue nSemValue=1
line:80 >>>> sem_getvalue nSemValue=0
line:81  A Worker...m_nCount=2
line:77 >>>> sem_getvalue nSemValue=0

line:59  send sem...
line:62 >>>> sem_getvalue nSemValue=1
line:99 >>>> sem_getvalue nSemValue=0
line:100 B Worker...m_nCount=3
line:96 >>>> sem_getvalue nSemValue=0

line:59  send sem...
line:62 >>>> sem_getvalue nSemValue=1
line:80 >>>> sem_getvalue nSemValue=0
line:81  A Worker...m_nCount=4
line:77 >>>> sem_getvalue nSemValue=0

line:59  send sem...
line:62 >>>> sem_getvalue nSemValue=1
line:99 >>>> sem_getvalue nSemValue=0
line:100 B Worker...m_nCount=5
line:96 >>>> sem_getvalue nSemValue=0

line:59  send sem...
line:62 >>>> sem_getvalue nSemValue=1
line:80 >>>> sem_getvalue nSemValue=0
line:81  A Worker...m_nCount=6
line:77 >>>> sem_getvalue nSemValue=0

line:59  send sem...
line:62 >>>> sem_getvalue nSemValue=1
line:99 >>>> sem_getvalue nSemValue=0
line:100 B Worker...m_nCount=7
line:96 >>>> sem_getvalue nSemValue=0

line:59  send sem...
line:62 >>>> sem_getvalue nSemValue=1
line:80 >>>> sem_getvalue nSemValue=0
line:81  A Worker...m_nCount=8
line:77 >>>> sem_getvalue nSemValue=0

line:59  send sem...
line:62 >>>> sem_getvalue nSemValue=1
line:99 >>>> sem_getvalue nSemValue=0
line:100 B Worker...m_nCount=9
line:96 >>>> sem_getvalue nSemValue=0

line:59  send sem...
line:62 >>>> sem_getvalue nSemValue=1
line:80 >>>> sem_getvalue nSemValue=0
line:81  A Worker...m_nCount=10
line:77 >>>> sem_getvalue nSemValue=0

**************  exit()  *****************
line:139 >>>> sem_getvalue nSemValue=0
************** sem_close  *****************
**************  sem_unlink  *****************
[root@VM-20-16-centos demo]# 

CMakeLists.txt

注意大小写敏感

CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
PROJECT(demo)

add_compile_options(-std=c++11)

INCLUDE_DIRECTORIES(
    ${CMAKE_CURRENT_LIST_DIR}/
)

FILE(GLOB COMMON
    ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp
)

FILE(GLOB SOURCES
    ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp
)

ADD_EXECUTABLE(
    ${PROJECT_NAME} 
    ${SOURCES}
    ${COMMON}
)

TARGET_LINK_LIBRARIES(
    ${PROJECT_NAME}
    pthread
)

编译运行

cmake .

make

./demo

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值