POSIX信号量和SystemV信号量作⽤相同,都是⽤于同步操作,达到⽆冲突的访问共享资源⺫的。 但POSIX可以⽤于线程间同步。
一个计数器+等待队列,计数器用来标记当前是否有资源可供操作,等待队列则是没有资源就将pcb加入队列中,等有资源的时候唤醒队列中的线程。
信号量的操作就是对计数器的+1/-1操作,当计数器<=0则表示没有资源,这时候陷入等待;如果别人释放了资源,唤醒等待。
信号量用于实现进程/线程之间的同步与互斥。
初始化信号量
int sem_init(sem_t *sem, int pshared, unsigned int value);
参数:
pshared:0表⽰线程间共享,⾮零表⽰进程间共享
value:信号量初始值
返回值:成功0;失败:-1
销毁信号量
int sem_destroy(sem_t *sem);
获取信号量(等待信号量)
功能:等待信号量,会将信号量的值减1
int sem_wait(sem_t *sem);判断计数器是否大于零,大于零表示有资源可操作,这时候计数器-1,如果小于等于0代表没有资源可操作,这时候则陷入等待
int sem_trywait();
int sem_timewait();
发布信号量
功能:发布信号量,表⽰资源使⽤完毕,可以归还资源了。将信号量值加1。
int sem_post(sem_t *sem);
实现线程同步
#include
#include
#include
#include
#include
#include
using namespace std;
sem_t sem;
void* productor(void* arg)
{
while(1)
{
sleep(1);
cout << "create noodle!!!" << endl;
sem_post(&sem);
}
return NULL;
}
void* consumer(void* arg)
{
while(1)
{
sem_wait(&sem);
cout << "eat noodle!!!" << endl;
}
return NULL;
}
int main()
{
pthread_t tid1,tid2;
sem_init(&sem, 0, 0);
pthread_create(&tid1, NULL, productor, NULL);
pthread_create(&tid2, NULL, consumer, NULL);
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
sem_destroy(&sem);
return 0;
}
实现线程互斥
#include
#include
#include
#include
#include
#include
using namespace std;
sem_t sem;
void* productor(void* arg)
{
while(1)
{
sem_wait(&sem);
cout << "create noodle!!!" << endl;
sem_post(&sem);
usleep(10);
}
return NULL;
}
void* consumer(void* arg)
{
while(1)
{
sem_wait(&sem);
cout << "eat noodle!!!" << endl;
sem_post(&sem);
usleep(10);
}
return NULL;
}
int main()
{
pthread_t tid1,tid2;
sem_init(&sem, 0, 1);
pthread_create(&tid1, NULL, productor, NULL);
pthread_create(&tid2, NULL, consumer, NULL);
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
sem_destroy(&sem);
return 0;
}
用信号量实现环形队列
/*用vector实现环形队列
* 使用信号量来对这个环形队列资源进行计数
* 两个信号量:
* 一个是空闲空间资源计数 等于vector节点数
* 一个是写入数据的空间计数 初始值为0
*/
#include
#include
#include
#include
#include
#include
using namespace std;
#define MAX_QUEUE 10
class RingQueue
{
private:
vector _q;
int _cap;
int _consumer_step;
int _productor_step;
sem_t _idle;
sem_t _data;
public:
RingQueue(int cap = MAX_QUEUE):_cap(cap),_q(cap)
{
_consumer_step = 0;
_productor_step = 0;
sem_init(&_idle, 0, cap);
sem_init(&_data, 0, 0);
}
~RingQueue()
{
sem_destroy(&_data);
sem_destroy(&_idle);
}
bool GetData(int& data)
{
sem_wait(&_data);
data = _q[_consumer_step++];
_consumer_step %= _cap;
sem_post(&_idle);
return true;
}
bool PutData(int data)
{
sem_wait(&_idle);
_q[_productor_step++] = data;
_productor_step %= _cap;
sem_post(&_data);
return true;
}
};
void* consumer(void* arg)
{
RingQueue *q = (RingQueue*)arg;
while(1)
{
int data;
q->GetData(data);
cout << "data:" << data << endl;
}
return NULL;
}
void* productor(void* arg)
{
RingQueue *q = (RingQueue*)arg;
int i = 0;
while(1)
{
q->PutData(i++);
cout << "put data:" << i << endl;
}
return NULL;
}
int main()
{
RingQueue q;
pthread_t tid1, tid2;
pthread_create(&tid1, NULL, consumer, (void*)&q);
pthread_create(&tid2, NULL, productor, (void*)&q);
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
return 0;
}