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; }