【Linux】POSIX信号量

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 <iostream>
#include<unistd.h>
#include<stdlib.h>
#include<semaphore.h>
#include<errno.h>
#include<pthread.h>
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 <iostream>
#include<unistd.h>
#include<stdlib.h>
#include<semaphore.h>
#include<errno.h>
#include<pthread.h>
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 <iostream>
#include<unistd.h>
#include<stdlib.h>
#include<pthread.h>
#include<semaphore.h>
#include<vector>
using namespace std;
#define MAX_QUEUE 10
class RingQueue
{
private:
    vector<int> _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;
}

猜你喜欢

转载自blog.csdn.net/yulong__li/article/details/85264629