c++之初级的消息队列及线程池模型
1.最近项目不是很忙,结合之前看的一些开源代码(skynet及其他github代码)及项目代码,抽空写了一个简单的任务队列当做练习。
2.介绍:
1)全局队列中锁的使用:多线程下,全局队列需要加锁,本例中封装了MutexGuard。操作全局队列之前,先在栈上创建一个临时锁对象,调用构造函数时加锁,对象销毁时调用析构函数从而解锁,减少了我们手动加锁,解锁的过程。
2)信号的使用:本例可以说是为了使用信号而使用信号,仅仅是为了熟悉信号机一些特性。 当程序以后台模式 跑起来以后,输入kill -USR1 %1 向程序发送SIGUSR1信号,从而使生产者生产一定数量的job,供消费者使用;消费者线程,在处理完全局队列以后sleep,等待生产者产生新任务; 输入 kill -USR2 %1, 改变变量状态,向信号监听线程发送结束通知,结束线程。
3)简单的线程池模型。
4)简单的线程间通信和同步方式示例。
5)简单的类模板的使用。
3.编译: 文件不多,偷懒没有写makefile文件,可自行加上。编译指令 : g++ -g -Wall -o test main.cpp mutex.cpp List.h mutex.h -lpthread
4:执行流程:
1)编译成功后,输入 ./mytest &。 以后台模式运行程序
2)此时所有consumer线程阻塞,等待生产者生产job; 一个producer线程阻塞在select处,等待读管道内的消息;一个signal_handler线程调用 pthread_sigwait( ... ) 等待 SIGUSR1 和 SIGUSR2 信号的到来。
可通过在控制台输入: kill -USR1 %1(ps: kill 指令用来产生信号 当以后台模式运行该进程时, %1用来获得该进程 id,因此该命令表示向 该进程发送 SIGUSR1 信号)进程发送SIGUSR1信号,被signal_handler捕捉到以后,生产job,唤醒consumer线程处理job,此流程可重复执行;当在控制台输入 kill -USR2 %1 时, 改变quit变量值,从而使得各个线程退出,进程结束。还有一个 spoliling 轮询线程,在全局队列不为空的情况下,及时唤醒consumer线程处理任务。可通过调整wakeup中的参数,调整唤醒consumer的频率。
5.参考:
1)UNIX环境高级编程。
2)https://github.com/idispatch/signaltest
3)https:github.com/cloudwu/skynet/skynet-src/skynet_start.c
水平有限,仅供参考,希望能对读者有所帮助。以上描述及以下源码有任何漏洞与不足,欢迎及时指正与交流。
6:源码:
main.cpp:
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/types.h>
#include <string.h>
#include <errno.h>
#include <signal.h> #include "List.h"
#include "mutex.h" #define THREAD_NUM 4
#define JOB_NUM 100 #define handle_error_en(en, msg) \
do{ errno = en; perror(msg); exit(EXIT_FAILURE); } while() using std::cout;
using std::endl;
using std::string;
using std::cin; struct monitor
{
int count;
pthread_cond_t cond;
pthread_mutex_t mutex;
int sleep;
int quit;
int pfds[];
}; struct sig
{
sigset_t set;
struct monitor *m;
}; typedef void (*thread_func)(void *arg, int value); //job call back
struct job
{
void *arg;
thread_func cb;
}; List<job *> g_list;
const int allowed_signals[] = {SIGUSR1, SIGUSR2, SIGQUIT}; static void
print_v(void *value, int pid)
{
printf("pid: %d, value: %d\n", pid, *(int*)value);
} static void
free_job(struct job *j)
{
if(j == NULL)
{
return;
} free(j->arg);
j->arg = NULL;
free(j);
j = NULL;
} static int
dispatch(int pid)
{
struct job *j = g_list.Pop();
if (j != NULL)
{
j->cb(j->arg, pid);
free_job(j);
return ;
} return -;
} static void *
consumer(void *arg)
{
struct monitor *m = (struct monitor *)arg;
int r = ; usleep();
int pid = pthread_self();
while(!m->quit)
{
r = dispatch(pid);
if (r < )
{
if(pthread_mutex_lock(&m->mutex) == )
{
++m->sleep;
cout << "thread : " << pid << " sleep" << endl;
if(!m->quit)
{
pthread_cond_wait(&m->cond, &m->mutex);
} -- m->sleep;
cout << "thread : " << pid << " wakeup" << endl;
if(pthread_mutex_unlock(&m->mutex))
{
fprintf(stderr, "unlock mutex error");
exit();
}
}
}
}
cout << "thread consumer quit " << endl;
return NULL;
} static void
free_monitor(struct monitor *m)
{
if(m == NULL)
{
return;
}
cout << "free monitor called" << endl;
close(m->pfds[]);
close(m->pfds[]); free(m);
cout << "free monitor over" << endl;
} static void
wakeup(struct monitor *m, int busy)
{
if (m->sleep >= m->count - busy)
{
// signal sleep worker, "spurious wakeup" is harmless
pthread_cond_signal(&m->cond);
}
} static struct job*
create_job()
{
struct job * j = (struct job *)calloc(, sizeof(*j));
if (j == NULL)
{
fprintf(stderr, "create_job failed");
return NULL;
} int v = rand();
j->arg = malloc(sizeof (int));
if (j->arg == NULL)
{
fprintf(stderr, "get arg failed");
return NULL;
}
memcpy(j->arg, &v, sizeof (int) );
j->cb = print_v; return j;
} static void *
producer(void *arg)
{ struct monitor *m = (struct monitor *)arg;
cout << "producer called" << endl;
int pid = pthread_self();
int state;
while(!m->quit)
{
fd_set fds;
FD_ZERO(&fds);
FD_SET(m->pfds[], &fds); state = select(m->pfds[] + , &fds, NULL, NULL, NULL);
if(state < )
{
if(errno == EINTR)
{
cout << "errno == EINTR" << endl;
continue;
}
break;
}
else if (state == )
{ }
else
{
char msg[];
memset(msg, , sizeof(msg));
read(m->pfds[], msg, sizeof(msg)); //only to clear up pipe.
msg[strlen(msg)] = '\0';
fprintf(stdout, "msgis: %s\n", msg);
fflush(stdout); if (FD_ISSET(m->pfds[], &fds))
{
if(strncmp(msg, "quit", strlen("quit")) == )
{
break;
} int i;
for (i = ; i < JOB_NUM; i++)
{
struct job *j = create_job();
if (j == NULL)
{
fprintf(stderr, "prodecer failed");
exit();
}
g_list.Push(j);
}
cout << "Thread " << "[" << pid << "]" << ": create " << JOB_NUM << " jobs" << endl;
wakeup(m, );
}
}
} cout << "thread producer quit" << endl;
return NULL;
} static int
check_g_list()
{
int len = g_list.get_job_num();
if(len == )
{
return -;
} return ;
} static void *
spoiling(void *arg)
{
struct monitor *m = (struct monitor *)arg;
cout << "spoiling called" << endl;
while(!m->quit)
{
int n = check_g_list();
if(n == )
{
break;
}
if(n < )
{
continue;
}
wakeup(m, );
} cout << "thread spoiling quit" << endl;
return NULL;
} static void
thread_create(pthread_t *pid, void *arg , void * (*pthread_func) (void *))
{
if(pthread_create(pid, NULL, pthread_func, arg) != )
{
fprintf(stderr, "create_thread failed");
exit();
}
} static void*
signal_handler(void *arg)
{
struct monitor *m = (struct monitor *)arg;
int isig, state; sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGUSR1);
sigaddset(&set, SIGUSR2);
sigaddset(&set, SIGTERM); cout << "signal_handler called" << endl;
for(;;)
{
state = sigwait(&set, &isig);
cout << "sigwait : " << isig << endl;
if(state != )
{
fprintf(stderr, "wrong state %d\n", state);
continue;
}
if(isig == SIGUSR1)
{
cout << "SIGUSR1 " << endl;
char msg[];
memset(msg, , sizeof(msg));
snprintf(msg, sizeof(msg), "signal_handler: received signal=%d(thread=%d)\n", isig, (int)pthread_self());
write(m->pfds[], msg, strlen(msg));
}
else if(isig == SIGUSR2)
{
cout << "SIGUSR2 " << endl;
pthread_mutex_lock(&m->mutex);
m->quit = ;
write(m->pfds[], "quit", strlen("quit"));
pthread_cond_broadcast(&m->cond);
pthread_mutex_unlock(&m->mutex); //when quit, send "quit" to producer or it will block on select break;
}
else
{
cout << "SIG OTHER quit" << endl;
break;
}
}
cout << "signal_handler quit" << endl;
return NULL;
} static void
start_thread()
{
pthread_t pids[THREAD_NUM + ];
struct monitor *m = (struct monitor *)malloc(sizeof(*m));//(struct monitor *)malloc(sizeof(*m));
if (m == NULL)
{
fprintf(stderr, "create monitor failed");
exit();
}
if(pipe(m->pfds))
{
fprintf(stderr, "%s: pipe failed\n", __FUNCTION__);
exit();
} m->count = THREAD_NUM;
m->sleep = ;
m->quit = ;
if(pthread_mutex_init(&(m->mutex), NULL) != || pthread_cond_init(&(m->cond), NULL) != )
{
fprintf(stderr, "mutex or cond init failed");
exit();
} int rc;
sigset_t set; sigemptyset(&set);
sigaddset(&set, SIGUSR1);
sigaddset(&set, SIGUSR2);
sigaddset(&set, SIGQUIT);
rc = pthread_sigmask(SIG_BLOCK, &set, NULL);
if(rc != )
{
fprintf(stderr, "%s pthread_sigmask failed\n", __FUNCTION__);
exit();
} thread_create(&pids[], m, signal_handler);
thread_create(&pids[], m, spoiling); //spoiling thread , check if the g_list is empty
thread_create(&pids[], m, producer); //producer thread int i;
for (i = ; i < THREAD_NUM + ; i++)
{
thread_create(&pids[i], m, consumer); //consumer thread
} for (i = ; i < THREAD_NUM + ; i++)
{
pthread_join(pids[i], NULL);
} free_monitor(m);
} int
main(int argc, char *argv[])
{
cout << "-----------------start---------------------" << endl;
start_thread();
cout << "------------------end----------------------" << endl;
}
mutex.h
#ifndef __MUTEX__H__
#define __MUTEX__H__ #include <list> #include <pthread.h> class MyMutex
{
public:
MyMutex(pthread_mutex_t& m);
~MyMutex(); void Lock();
void UnLock(); private:
pthread_mutex_t& m_m; }; class MyMutexGuard
{
public:
MyMutexGuard(pthread_mutex_t& m);
~MyMutexGuard(); private:
MyMutex mm; }; #endif
mutex.cpp
#include "mutex.h" MyMutex::MyMutex(pthread_mutex_t& m) : m_m(m)
{
} MyMutex::~MyMutex()
{
} void MyMutex::Lock()
{
pthread_mutex_lock(&m_m);
} void MyMutex::UnLock()
{
pthread_mutex_unlock(&m_m);
} MyMutexGuard::MyMutexGuard(pthread_mutex_t& m):mm(m)
{
mm.Lock();
} MyMutexGuard::~MyMutexGuard()
{
mm.UnLock();
}
List.h
#ifndef __LIST_HEAD__
#define __LIST_HEAD__ #include "mutex.h" #include <list>
using std::list;
#ifndef _WIN32
#include <pthread.h>
#endif template<typename T>
class List
{
public:
List();
List(const list<T> &l);
virtual ~List(); T Pop();
void Push(const T t);
bool Empty();
int get_job_num();
private:
void init();
void destroy(); private:
bool m_init;
list<T> my_list;
pthread_mutex_t mm; }; #include "List.cpp" #endif
List.cpp
#include "List.h"
#include "mutex.h" template<typename T>
List<T>::List()
:m_init(false)
{ } template<typename T>
List<T>::List(const list<T> &l)
:m_init(false)
{ } template<typename T>
List<T>::~List()
{
destroy();
} template<typename T>
void List<T>::Push(const T t)
{
MyMutexGuard g(mm);
my_list.push_back(t);
} template<typename T>
T List<T>::Pop()
{
MyMutexGuard g(mm); if(my_list.empty())
{
return NULL;
}
else
{
T tt = my_list.front();
my_list.pop_front(); return tt;
}
} template<typename T>
bool List<T>::Empty()
{
MyMutexGuard g(mm);
return my_list.empty();
} template<typename T>
void List<T>::init()
{
if(!m_init)
{
m_init = (pthread_mutex_init(&mm, NULL) == );
} return m_init;
} template<typename T>
void List<T>::destroy()
{
pthread_mutex_destroy(&mm);
} template<typename T>
int List<T>::get_job_num()
{
MyMutexGuard g(mm);
return my_list.size();
}
c++之初级的消息队列及线程池模型的更多相关文章
- C++11消息队列 + Qt线程池 + QRunnable执行任务简单模型
1.模板类queue,包含头文件<queue>中,是一个FIFO队列. queue.push():在队列尾巴增加数据 queue.pop():移除队列头部数据 queue.font():获 ...
- 自定义ThreadPoolExecutor带Queue缓冲队列的线程池 + JMeter模拟并发下单请求
.原文:https://blog.csdn.net/u011677147/article/details/80271174 拓展: https://github.com/jwpttcg66/GameT ...
- 基于java.util.logging实现轻量级日志记录库(增加根据当前类class初始化,修复线程池模型(javaEE)下的堆栈轨迹顺序与当前调用方法不一致问题)
前言: 本章介绍自己写的基于java.util.logging的轻量级日志记录库(baseLog). 该版本的日志记录库犹如其名,baseLog,是个实现日志记录基本功能的小库,适合小型项目使用,方便 ...
- C# 模拟一个处理消息队列的线程类 Message Queue
// 模拟一个处理消息队列的类 class MessageHandler { // 消息队列 private Queue<string> messageQue = new Queue< ...
- Android -- 网络图片查看器,网络html查看器, 消息机制, 消息队列,线程间通讯
1. 原理图 2. 示例代码 (网络图片查看器) (1) HttpURLConnection (2) SmartImageView (开源框架:https://github.com/loopj/an ...
- 【Java并发】并发队列与线程池
并发队列 阻塞队列与非阻塞队 ConcurrentLinkedQueue BlockingQueue ArrayBlockingQueue LinkedBlockingQueue PriorityBl ...
- python 线程队列、线程池、全局解释器锁GIL
一.线程队列 队列特性:取一个值少一个,只能取一次,没有值的时候会阻塞,队列满了,也会阻塞 queue队列 :使用import queue,用法与进程Queue一样 queue is especial ...
- 第三十四天- 线程队列、线程池(map/submit/shutdown/回调函数)
1.线程列队 queue队列 :使用import queue,用法与进程Queue一样 class queue.Queue(maxsize=0) # 先进先出: q = queue.Queue(3) ...
- [Go]TCP服务中增加消息队列与工作池
之前的处理中每一个连接都会创建一个主groutine , 每个连接中的主groutine中创建出读groutine 和写groutine 每个连接处理业务再单独开出一个groutine ,这样如果有1 ...
随机推荐
- js 获取Array数组 最大值 最小值
https://stackoverflow.com/questions/1669190/find-the-min-max-element-of-an-array-in-javascript // 错误 ...
- POJ1470Closest Common Ancestors 最近公共祖先LCA 的 离线算法 Tarjan
该算法的详细解释请戳: http://www.cnblogs.com/Findxiaoxun/p/3428516.html #include<cstdio> #include<alg ...
- Mad Counting---LightOJ1148(好任性的过了)
题目链接:http://lightoj.com/volume_showproblem.php?problem=1148 已知有n个人,并且每个人都知道除自己之外还有m个人与自己支持的队一样,让我们求至 ...
- java爬取网页内容 简单例子(1)——使用正则表达式
[本文介绍] 爬取别人网页上的内容,听上似乎很有趣的样子,只要几步,就可以获取到力所不能及的东西,例如呢?例如天气预报,总不能自己拿着仪器去测吧!当然,要获取天气预报还是用webService好.这里 ...
- (2.13)备份与还原--sql server数据库主要状态和切换路径
SQLSERVER数据库主要状态和切换路径 关键词:数据库状态 一个SQLSERVER数据库会处于很多种状态,例如 ONLINE .RESTORING .RECOVERING .RECOVERY_PE ...
- apache-storm-1.0.3安装部署
CentOS7-1 CentOS7-2 CentOS7-3 CentOS7-4 nimbus supervisor supervisor supervisor core(UI) 1.首 ...
- Web UI 自动化单个xpath抓取插件详解
原文地址http://blog.csdn.net/kaka1121/article/details/51878346 单个控件获取 需求: 右键到某个控件上,就能获取到至多三个可以唯一定位该元素的相对 ...
- python全栈开发从入门到放弃之推导式详解
variable = [out_exp_res for out_exp in input_list if out_exp == 2] out_exp_res: 列表生成元素表达式,可以是有返回值的函数 ...
- 以二进制方式读取图片保存到string
procedure TForm1.BitBtn1Click(Sender: TObject);var StringStream : TStringStream; FSize : integer; ...
- Extjs3.4 grid中添加一列复选框
var sm = new Ext.grid.CheckboxSelectionModel(); var cm = new Ext.grid.ColumnModel( [ sm, new Ext.gri ...