posix信号量机制

posix为可移植的操作系统接口标准,定义了操作系统应该为应用程序提供的接口标准

信号量机制是我们在操作系统中学到的知识,可以用来解决同步和互斥的问题,它只能被两个标准的原语wait(S)和Signal(S)来访问,也就是p操作和v操作。信号量的概念在system v 和posix 中都有,但是它们两者的具体作用是有区别的。system v版本的信号量用于实现进程间的通信,而posix版本的信号量主要用于实现线程之间的通信,两者的主要区别在于信号量和共享内存。

区别

system v版本的信号量是跟随于内核存在的,它的接口是:semget,semctl,semop

posix版本的信号量支持无命名的信号量和有命名的信号量,效率较高。

(1)有命名的信号量一般用于进程同步,使用文件进行关联,该部分的信号量是随着内核而存在的,主要接口有:sem_open,sem_close,sem_unlink.

(2)无命名的信号量一般用于线程的同步,当进程终止时,它也就消亡了,主要接口有:sem_init,sem_destory,sem_wait,sem_post.】

 无名信号量下的通信机制属于共享内存的情况,可以实现进程中多个线程之间的同步与互斥。而命名信号量通常用于不共享内存的情况下。

//有命名的信号量函数
#include <fcntl.h>          
#include <sys/stat.h>       
#include <semaphore.h>
sem_t *sem_open(const char *name, int oflag);
sem_t *sem_open(const char *name, int oflag, mode_t mode, unsigned int value);
int sem_close(sem_t *sem);
int sem_unlink(const char *name);
//无命名的信号量函数
用于实现线程间通信的信号量函数:
初始化信号量: 
int sem_init(sem_t *sem, int pshared, unsigned int value); 
//sem为指向信号量结构的一个指针;
//pshared不为0时此信号量在进程间共享,否则只能为当前进程的所有线程共享;
//value给出了信号量的初始值。 

销毁信号量: 
int sem_destroy(sem_t *sem);
//当我们使用完信号量后,对其进行销毁
 
等待信号量 
int sem_wait(sem_t *sem); 
//被用来阻塞当前线程直到信号量sem的值大于0,解除阻塞后将sem的值减一,表明公共资源经使用后减少

发布信号量: 
int sem_post(sem_t *sem);
//用来增加信号量的值,当有线程阻塞在这个信号量上时,调用这个函数会使其中的一个线程不在阻塞,选择机制同样是由线程的调度策略决定的。

posix互斥锁(同一时刻只能有一个进程访问该资源,一旦访问后立即上锁,访问完进行解锁,进程间是互斥的)

#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t *mutex, 
                       const pthread_mutexattr_t *mutexattr);		
//互斥锁初始化, 为未锁住状态。
int pthread_mutex_lock(pthread_mutex_t *mutex);	//互斥锁上锁
int pthread_mutex_trylock(pthread_mutex_t *mutex);	//互斥锁判断上锁
int pthread_mutex_unlock(pthread_mutex_t *mutex);	//互斥锁解锁
int pthread_mutex_destroy(pthread_mutex_t *mutex);	//消除互斥锁

下面使用posix信号量来实现我们在操作系统课程中学到的知识,生产者和消费者之间的同步和互斥的关系

  • 生产者和消费者之间的同步关系
  • #include <stdio.h>
    #include <stddef.h>
    #include<pthread.h>
    #include<time.h>
    #include<semaphore>
    #define SQUEUEMAX 1000
    typedef char SeqQueueType;
    
    typedef struct SeqQueue{
      SeqQueueType data[SQUEUEMAX];
      size_t head;
      size_t tail;
      size_t size;
    }SeqQueue;
    
    pthread_mutex_t mutex;//互斥信号量mutex
    sem_t p;//信号量p,用于标识空闲缓冲的资源,可供生产者进行生产
    sem_t c;//信号量c,用于标识满缓冲区的资源,可供消费者消费
    void SeqQueueInit(SeqQueue* q)//初始化顺序式队列
    {
      if(q == NULL)
      {
        return;
      }
    
      q->head = 0;
      q->tail = 0;
      q->size = 0;
    
      return;
    }
    
    void DestroySeqQueue(SeqQueue* q)//销毁顺序式队列
    {
      if(q == NULL)
      {
        return;
      }
    
      q->head = 0;
      q->tail = 0;
      q->size = 0;
    
      return;
    }
    
    void SeqQueuePush(SeqQueue* q, SeqQueueType value)//入顺序式队列
    {
      if(q == NULL)
      {
        return;
      }
      if(q->size >= SQUEUEMAX)
      {
        return;
      }
    
      if(q->size == 0)
      {
        q->data[q->head] = value;
        ++q->tail;
        ++q->size;
      }
      else
      {
        q->data[q->tail++] = value;
        ++q->size;
      }
    
      if(q->tail >= SQUEUEMAX)
      {
        q->tail = 0;
      }
    
      return;
    }
    
    void SeqQueuePop(SeqQueue* q)//出顺序式队列
    {
      if(q == NULL)
      {
        return;
      }
      if(q->size == 0)
      {
        return;
      }
    
      ++q->head;
      if(q->head >= SQUEUEMAX)
      {
        q->head = 0;
      }
      --q->size;
    
      return;
    }
    
    int SeqQueueTop(SeqQueue* q, SeqQueueType* value)//获取队首
    {
      if(q == NULL || value == NULL)
      {
        return -1;
      }
    
      *value = q->data[q->head];
      return 1;
    }
    void* consumers(void* arg)
    {
        SeqQueue*q=(SeqQueue* )arg;//定义初始队列
        int cmsg;
        while(1)
        {
            sem_wait(&c);//P(c)操作
            pthread_mutex_lock(&mutex);//P(mutex)操作
            int ret=SeqQueueTop(q,&cmsg);//取队首元素,表示消费者取到的元素
            SeqQueuePop(q);//出队列,消费者取出元素
            if(ret>0)
            {
                printf("consumer get:%d\n",&cmsg);
                pthread_mutex_unlock(&mutex);//V(mutex)操作
                sem_post(&p);//V(p)操作
            }
        }
    }
    void* productor(void* arg)
    {
        SeqQueue* q=(SeqQueue*)arg;
        int msg=2;
        while(1)
        {
            usleep(10000);//先延迟挂起生产者进程
            sem_wait(&p);//P(p)操作
            pthread_mutex_lock(&mutex);//P(mutex)操作
            SeqQueuePush(q,msg);//生产者放入生产的元素
            printf("producter:%d\n",&msg);
            pthread_mutex_unlock(&mutex);//V(mutex)操作
            sem_post(&c);//V(c)操作
            msg++;
        }
    
    }
    int main()
    {
        pthread_t id1,id2;
        pthread_mutex_init(&mutex,NULL);//互斥锁的初始化
    
        sem_init(&c,0,0);//设置信号量c初始值为0,由当前进程的线程共享
        sem_init(&p,0,1);//设置信号量p初始值为1,由当前进程的线程共享
    
        SeqQueue q;
        SeqQueueInit(&q);
    
        pthread_create(&id1,NULL,consumers,(void**)&q);//创建消费者线程
        pthread_create(&id2,NULL,productor,(void**)&q);//创建生产者线程
    
        pthread_join(id1,NULL);//线程间的同步操作,等待线程的结束
        pthread_join(id2,NULL);
    
        pthread_mutex_destroy(&mutex);
        sem_destroy(&c);
        sem_destroy(&p);
        return 0;
    }
    

猜你喜欢

转载自blog.csdn.net/qq_40170007/article/details/88083275