POSIX
信号量和
SystemV
信号量作用相同,都是用于同步操作,达到无冲突的访问共享资源目的。 但
POSIX
可以用于线程间同步。
初始化信号量
#include <semaphore.h> int sem_init(sem_t *sem, int pshared, unsigned int value);
参数:pshared:0表示线程间共享,非零表示进程间共享
value:信号量初始值
销毁信号量
int sem_destroy(sem_t *sem);
等待信号量
功能:等待信号量,会将信号量的值减1 int sem_wait(sem_t *sem); //P()
发布信号量
功能:发布信号量,表示资源使用完毕,可以归还资源了。将信号量值加1。
int sem_post(sem_t *sem);//V()
多线程程序中,使用信号量需遵守以下几条规则:
- 信号量的值不能小于 0;
- 有线程访问资源时,信号量执行“减 1”操作,访问完成后再执行“加 1”操作;
- 当信号量的值为 0 时,想访问资源的线程必须等待,直至信号量的值大于 0,等待的线程才能开始访问
基于环形队列的生产消费模型
环形队列采用数组模拟,用模运算来模拟环状特性
环形结构起始状态和结束状态都是一样的,不好判断为空或者为满,所以可以通过加计数器或者标记位来判断满或者空。另外也可以预留一个空的位置,作为满的状态
但是我们现在有信号量这个计数器,就很简单的进行多线程间的同步过程
ring_queue.hpp
#include <iostream>
#include <pthread.h>
#include <unistd.h>
#include <semaphore.h>
#include<vector>
namespace Ns_Ring
{
template <class T>
class ring
{
public:
ring(size_t cap = 5)
:_cap(cap)
,_v(cap)
{
_c_step = _p_step = 0;
sem_init(&_is_empty,0,cap);
sem_init(&_is_data,0,0);
}
void Pop(T*out)
{
sem_wait(&_is_data);
*out = _v[_c_step];
_c_step++;
_c_step %= _cap;
sem_post(&_is_empty);
}
void Push(const T & data)
{
sem_wait(&_is_empty);
_v[_p_step] = data;
++_p_step;
_p_step %= _cap;
sem_post(&_is_data);
}
~ring()
{
sem_destroy(&_is_empty);
sem_destroy(&_is_data);
}
private:
size_t _cap;
std::vector<T> _v;
sem_t _is_empty;
sem_t _is_data;
int _c_step;
int _p_step;
};
}
CpTest.cpp
#include "ring_queue.hpp"
#include<time.h>
void *consumer(void *args)
{
Ns_Ring::ring<int>* r = (Ns_Ring::ring<int>*) args;
while(true)
{
int data = 0;
r->Pop(&data);
std::cout<<"消费者消费:"<<data<<std::endl;
}
}
void *producter(void *args)
{
Ns_Ring::ring<int>* r = (Ns_Ring::ring<int>*) args;
while(true)
{
int data = rand() % 20 + 1;
r->Push(data);
std::cout<<"生产者生产"<<data<<std::endl;
sleep(1);
}
}
int main()
{
pthread_t c,p;
Ns_Ring::ring<int>* r = new Ns_Ring::ring<int>();
pthread_create(&c,nullptr,consumer,(Ns_Ring::ring<int>*)r);
pthread_create(&p,nullptr,producter,(Ns_Ring::ring<int>*)r);
pthread_join(c,nullptr);
pthread_join(p,nullptr);
}
以上是单生产者消费者模型,如果需要实现多生产者多消费者需要加锁,代码如下:
ring_queue.hpp
#include <iostream>
#include <pthread.h>
#include <unistd.h>
#include <semaphore.h>
#include <vector>
namespace Ns_Ring
{
template <class T>
class ring
{
public:
ring(size_t cap = 5)
: _cap(cap), _v(cap)
{
_c_step = _p_step = 0;
sem_init(&_is_empty, 0, cap);
sem_init(&_is_data, 0, 0);
pthread_mutex_init(&_mutex, nullptr);
}
void Pop(T *out)
{
sem_wait(&_is_data);
pthread_mutex_lock(&_mutex);
*out = _v[_c_step];
_c_step++;
_c_step %= _cap;
pthread_mutex_unlock(&_mutex);
sem_post(&_is_empty);
}
void Push(const T &data)
{
sem_wait(&_is_empty);
pthread_mutex_lock(&_mutex);
_v[_p_step] = data;
++_p_step;
_p_step %= _cap;
pthread_mutex_unlock(&_mutex);
sem_post(&_is_data);
}
~ring()
{
sem_destroy(&_is_empty);
sem_destroy(&_is_data);
pthread_mutex_destroy(&_mutex);
}
private:
size_t _cap;
std::vector<T> _v;
sem_t _is_empty;
sem_t _is_data;
int _c_step;
int _p_step;
pthread_mutex_t _mutex;
};
}
CpTest.cpp
#include "ring_queue.hpp"
#include<time.h>
void *consumer(void *args)
{
Ns_Ring::ring<int>* r = (Ns_Ring::ring<int>*) args;
while(true)
{
int data = 0;
r->Pop(&data);
std::cout<<"消费者"<<pthread_self()<<"消费:"<<data<<std::endl;
}
}
void *producter(void *args)
{
Ns_Ring::ring<int>* r = (Ns_Ring::ring<int>*) args;
while(true)
{
int data = rand() % 20 + 1;
r->Push(data);
std::cout<<"生产者"<<pthread_self()<<"生产"<<data<<std::endl;
sleep(2);
}
}
int main()
{
pthread_t c,p;
pthread_t c1,c2,c3,c4;
pthread_t p1,p2,p3,p4;
Ns_Ring::ring<int>* r = new Ns_Ring::ring<int>();
pthread_create(&c,nullptr,consumer,(Ns_Ring::ring<int>*)r);
pthread_create(&c1,nullptr,consumer,(Ns_Ring::ring<int>*)r);
pthread_create(&c2,nullptr,consumer,(Ns_Ring::ring<int>*)r);
pthread_create(&c3,nullptr,consumer,(Ns_Ring::ring<int>*)r);
pthread_create(&c4,nullptr,consumer,(Ns_Ring::ring<int>*)r);
pthread_create(&p,nullptr,producter,(Ns_Ring::ring<int>*)r);
pthread_create(&p1,nullptr,producter,(Ns_Ring::ring<int>*)r);
pthread_create(&p2,nullptr,producter,(Ns_Ring::ring<int>*)r);
pthread_create(&p3,nullptr,producter,(Ns_Ring::ring<int>*)r);
pthread_create(&p4,nullptr,producter,(Ns_Ring::ring<int>*)r);
pthread_join(c,nullptr);
pthread_join(p,nullptr);
}
下面我们实现在循环队列中加入任务代码如下:
ring_queue.hpp
#include <iostream>
#include <pthread.h>
#include <unistd.h>
#include <semaphore.h>
#include <vector>
namespace Ns_Ring
{
template <class T>
class ring
{
public:
ring(size_t cap = 5)
: _cap(cap), _v(cap)
{
_c_step = _p_step = 0;
sem_init(&_is_empty, 0, cap);
sem_init(&_is_data, 0, 0);
pthread_mutex_init(&_mutex, nullptr);
}
void Pop(T *out)
{
sem_wait(&_is_data);
pthread_mutex_lock(&_mutex);
*out = _v[_c_step];
_c_step++;
_c_step %= _cap;
pthread_mutex_unlock(&_mutex);
sem_post(&_is_empty);
}
void Push(const T &data)
{
sem_wait(&_is_empty);
pthread_mutex_lock(&_mutex);
_v[_p_step] = data;
++_p_step;
_p_step %= _cap;
pthread_mutex_unlock(&_mutex);
sem_post(&_is_data);
}
~ring()
{
sem_destroy(&_is_empty);
sem_destroy(&_is_data);
pthread_mutex_destroy(&_mutex);
}
private:
size_t _cap;
std::vector<T> _v;
sem_t _is_empty;
sem_t _is_data;
int _c_step;
int _p_step;
pthread_mutex_t _mutex;
};
}
Task.hpp
#include <iostream>
namespace Ns_Task
{
class task
{
public:
task()
{
}
task(const int &x, const int &y, const char op)
: _x(x), _y(y), _op(op)
{
}
int run()
{
int res = 0;
switch (_op)
{
case '+':
res = _x + _y;
break;
case '-':
res = _x - _y;
break;
case '*':
res = _x * _y;
break;
case '/':
res = _x / _y;
break;
case '%':
res = _x % _y;
break;
default:
break;
}
return res;
}
~task()
{
}
private:
int _x;
int _y;
char _op;
};
}
CpTest.cpp
#include "ring_queue.hpp"
#include<time.h>
#include"Task.hpp"
void *consumer(void *args)
{
Ns_Ring::ring<Ns_Task::task>* r = (Ns_Ring::ring<Ns_Task::task>*) args;
while(true)
{
Ns_Task::task t;
r->Pop(&t);
std::cout<<"消费数据是:"<<t.run()<<std::endl;
/*
int data = 0;
r->Pop(&data);
std::cout<<"消费者"<<pthread_self()<<"消费:"<<data<<std::endl;
*/
}
}
void *producter(void *args)
{
Ns_Ring::ring<Ns_Task::task>* r = (Ns_Ring::ring<Ns_Task::task>*) args;
while(true)
{
int x = rand()% 20 + 1;
int y = rand()% 20 + 1;
char op = "+-*/%"[rand() % 5];
Ns_Task::task t(x,y,op);
std::cout<<"生产数据是:"<<x<<op<<y<<std::endl;
r->Push(t);
sleep(2);
/*
int data = rand() % 20 + 1;
r->Push(data);
std::cout<<"生产者"<<pthread_self()<<"生产"<<data<<std::endl;
sleep(2);
*/
}
}
int main()
{
pthread_t c,p;
pthread_t c1,c2,c3,c4;
pthread_t p1,p2,p3,p4;
Ns_Ring::ring<Ns_Task::task>* r = new Ns_Ring::ring<Ns_Task::task>;
pthread_create(&c,nullptr,consumer,(Ns_Ring::ring<Ns_Task::task>*)r);
pthread_create(&c1,nullptr,consumer,(Ns_Ring::ring<Ns_Task::task>*)r);
pthread_create(&c2,nullptr,consumer,(Ns_Ring::ring<Ns_Task::task>*)r);
pthread_create(&c3,nullptr,consumer,(Ns_Ring::ring<Ns_Task::task>*)r);
pthread_create(&c4,nullptr,consumer,(Ns_Ring::ring<Ns_Task::task>*)r);
pthread_create(&p,nullptr,producter,(Ns_Ring::ring<Ns_Task::task>*)r);
pthread_create(&p1,nullptr,producter,(Ns_Ring::ring<Ns_Task::task>*)r);
pthread_create(&p2,nullptr,producter,(Ns_Ring::ring<Ns_Task::task>*)r);
pthread_create(&p3,nullptr,producter,(Ns_Ring::ring<Ns_Task::task>*)r);
pthread_create(&p4,nullptr,producter,(Ns_Ring::ring<Ns_Task::task>*)r);
pthread_join(c,nullptr);
pthread_join(p,nullptr);
}