目录
最终目标:
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