1)概念:
同步(synchronization)指的是多个任务(线程)按照约定的顺序相互配合完成一件事情
2)信号量:
通过信号量实现同步操作;由信号量来决定线程是继续运行还是阻塞等待
信号量代表某一类资源,其值表示系统中该资源的数量
信号量是一个受保护的变量,只能通过三种操作来访问:初始化、P操作(申请资源)、V操作(释放资源)
信号量的值为非负整数
3)函数接口
int sem_init(sem_t *sem, int pshared, unsigned int value)
功能:初始化信号量
参数: sem:初始化的信号量对象
pshared:信号量共享的范围(0: 线程间使用 非0:1进程间使用)
value:信号量初值
返回值:成功 0
失败 -1
int sem_wait(sem_t *sem)
功能:申请资源 P操作
参数:sem:信号量对象
返回值:成功 0
失败 -1
注:此函数执行过程,先对信号量进行减1,当信号量的值大于等于0时,表示有资源可以用,则继续执行;当信号量的值小于0时,表示没有资源可以使用,函数阻塞
int sem_post(sem_t *sem)
功能:释放资源 V操作
参数:sem:信号量对象
返回值:成功 0
失败 -1
注:释放一次信号量的值加1,函数不阻塞
练习:通过线程实现数据的输入输出,主线程循环从终端输入,线程函数将数据循环输出。
两个线程谁先执行是不知道的,如果先执行子进程执行函数sem_wait(p操作 消费着)因为初始化的时候资源为零 那么p操作减一就小于零了那么子进程就会阻塞在这个地方,然后看主函数scanf用户没有输入的话也是在阻塞。所以这两个线程都在阻塞,如果用户输入的话就会继续执行函数sem_post(v操作 生产者)资源加一 ,v操作加一后 p操作就会对该资源进行消费然后减一。
看红色
如果你一次输入的字符超过32个的话
先看红色的情况:
理想情况下fgets先读31个然后去执行函数sem_post(v操作生产者)然后子进程执行函数sem_wait(p操作消费者)然后打印完之后再去把主线程缓存区里面的读到buf中 然后v操作加一 再然后p操作减一
不理想情况下当v操作(生产者)释放资源后 p操作(消费者)没有申请资源 那么fgets会从缓存区中把剩下的读到buf中 就把buf以前的值给覆盖了 v操作(生产者)加一 那么子进程要申请资源的话就会打印两次一样的东西。
红蓝结合就是防止那种不理想的情况严格保证读一次打印一次
先执行那个进程也是不知道的,如果是子进程那么执行sem_wait(&sem)会进行阻塞,就会执行主进程执行sem_wait(&sem1)因为一开始有资源就是继续执行fgets然后读32个后执行v操作(生产者)加一 如果这是子进程的p操作(消费者)没有及时申请资源 那么在执行主函数时执行sem_wait(&sem1)因为信号为零那么就会一直阻塞 所以子进程的p操作一定会执行 然后进行打印 然后执行sem_post(&sem1)v操作进行加一再执行主进程里的sem_wait(&sem1) 然后依次循环。