线程同步---信号量

xiaoxiao2021-02-28  97

进化版的互斥锁(1 --> N)

         由于互斥锁的粒度比较大,如果我们希望在多个线程间对某一对象的部分数据进行共享,使用互斥锁是没有办法实现的,只能将整个数据对象锁住。这样虽然达到了多线程操作共享数据时保证数据正确性的目的,却无形中导致线程的并发性下降。线程从并行执行,变成了串行执行。与直接使用单进程无异。

         信号量,是相对折中的一种处理方式,既能保证同步,数据不混乱,又能提高线程并发。

主要应用函数:

         sem_init函数

         sem_destroy函数

         sem_wait函数

         sem_trywait函数  

         sem_timedwait函数      

         sem_post函数

以上6 个函数的返回值都是:成功返回0,失败返回-1,同时设置errno。(注意,它们没有pthread前缀)

         sem_t类型,本质仍是结构体。但应用期间可简单看作为整数,忽略实现细节(类似于使用文件描述符)。

sem_t sem; 规定信号量sem不能 < 0。头文件 <semaphore.h>

信号量基本操作:

sem_wait:        1. 信号量大于0,则信号量--                (类比pthread_mutex_lock)

           |                     2.信号量等于0,造成线程阻塞

         对应

           |

         sem_post:     将信号量++,同时唤醒阻塞在信号量上的线程         (类比pthread_mutex_unlock)

但,由于sem_t的实现对用户隐藏,所以所谓的++、--操作只能通过函数来实现,而不能直接++、--符号。

信号量的初值,决定了占用信号量的线程的个数。

sem_init函数

初始化一个信号量

         int sem_init(sem_t *sem, int pshared, unsigned int value);

         参1:sem信号量 

参2:pshared取0用于线程间;取非0(一般为1)用于进程间 

参3:value指定信号量初值

sem_destroy函数

销毁一个信号量

         int sem_destroy(sem_t *sem);

sem_wait函数

给信号量加锁 --

         int sem_wait(sem_t *sem);

sem_post函数

给信号量解锁 ++

          int sem_post(sem_t*sem); 

sem_trywait函数

尝试对信号量加锁 --    (与sem_wait的区别类比lock和trylock)

          int sem_trywait(sem_t *sem);      

sem_timedwait函数

限时尝试对信号量加锁 --

         int sem_timedwait(sem_t *sem, const struct timespec*abs_timeout);

         参2:abs_timeout采用的是绝对时间。                      

         定时1秒:

                   time_tcur = time(NULL); 获取当前时间。

struct timespec t;    定义timespec 结构体变量t

                   t.tv_sec= cur+1; 定时1秒

                   t.tv_nsec= t.tv_sec +100;

sem_timedwait(&sem, &t); 传参

/*信号量实现 生产者 消费者问题*/ #include <stdlib.h> #include <unistd.h> #include <pthread.h> #include <stdio.h> #include <semaphore.h> #define NUM 5                int queue[NUM];                                     //全局数组实现环形队列 sem_t blank_number, product_number;                 //空格子信号量, 产品信号量 void *producer(void *arg) {     int i = 0;     while (1) {         sem_wait(&blank_number);                    //生产者将空格子数--,为0则阻塞等待         queue[i] = rand() % 1000 + 1;               //生产一个产品         printf("----Produce---%d\n", queue[i]);                 sem_post(&product_number);                  //将产品数++         i = (i+1) % NUM;                            //借助下标实现环形         sleep(rand()%3);     } } void *consumer(void *arg) {     int i = 0;     while (1) {         sem_wait(&product_number);                  //消费者将产品数--,为0则阻塞等待         printf("-Consume---%d\n", queue[i]);         queue[i] = 0;                               //消费一个产品          sem_post(&blank_number);                    //消费掉以后,将空格子数++         i = (i+1) % NUM;         sleep(rand()%3);     } } int main(int argc, char *argv[]) {     pthread_t pid, cid;     sem_init(&blank_number, 0, NUM);                //初始化空格子信号量为5     sem_init(&product_number, 0, 0);                //产品数为0     pthread_create(&pid, NULL, producer, NULL);     pthread_create(&cid, NULL, consumer, NULL);     pthread_join(pid, NULL);     pthread_join(cid, NULL);     sem_destroy(&blank_number);     sem_destroy(&product_number);     return 0; }

转载请注明原文地址: https://www.6miu.com/read-57973.html

最新回复(0)