买票问题
这是一个在多线程中必遇到的问题, 多个线程抢一张票, 如果不加限制会出现买票 卖出负票或者
多个线程买重票的问题
所以线程在访问临界资源时应该上锁
出现负票的原因
线程 1 2 同时 1票
线程二 取 1票 ->判断1票可以 -> 保存上下文 切换->
线程1 执行完 1 - 1写回内存 票 0
切到线程二 (由上下文得知 已经进行过判断 直接运算) 0 -1 = -1 写回内存 票 -1
pthread下的互斥锁
//创建一个锁
pthread_mutex_t mutex;
//锁还可以一次性用宏初始化(静态初始化)
mutex = PTHREAD_MUTEX_INITIALIZER
//将锁初始化(动态初始化)
pthread_mutex_init(&mutex, NULL);
//上锁
pthread_mutex_lock(&mutex);
//放锁
pthread_mutex_unlock(&mutex);
//锁用完销毁锁
pthread_mutex_destory(&mutex, NULL);
加锁版本的买票系统
#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int tickets = 1000;
void* sell_tickets(void* arg)
{
while(1)
{
pthread_mutex_lock(&mutex);
if(tickets <= 0)
{
printf("sell out\n");
pthread_mutex_unlock(&mutex);
return;
}
char* id = (char*) arg;
usleep(1000);
tickets--;
printf("%s sells one ticket ,left %d ticket\n", id, tickets);
pthread_mutex_unlock(&mutex);
}
}
int main()
{
pthread_t thread1,thread2, thread3;
pthread_create(&thread1, NULL, sell_tickets, "thread1");
pthread_create(&thread2, NULL, sell_tickets, "thread2");
pthread_create(&thread3, NULL, sell_tickets, "thread3");
pthread_join(thread1,NULL);
pthread_join(thread2,NULL);
pthread_join(thread3,NULL);
return 0;
}
生产消费者模型
分析问题
消费者和消费者之前是互斥的, 那么就需要在众多消费者中设置一把互斥锁
生产者和生产者之间也是互斥的.那么就需要在众多生产者中设置一把一把互斥锁
到这里就 实现了生产者和消费者的互斥, 还剩下一个问题是要解决生产消费者之间的同步问题
当生产者生产一个产品后,就要通知消费者来取产品,
当消费者消费一个产品后,就要通知生产者去生产产品
我们发现,通知这个动作就是 发信号,这就用到了线程中的条件变量
条件变量函数接口
1. 初始化条件变量
宏常量静态初始化
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
函数动态初始化
#include <pthread.h>
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
2.等待和通知条件变量
#include <pthread.h>
int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime);
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_signal(pthread_cond_t *cond);
四个函数分别是
等待函数: 时间内等待,普通等待,
唤醒函数: 广播唤醒,单点唤醒
至于为什么条件变量后面要将锁作为参数传入,详见:多线程中 关于条件变量和互斥锁的疑惑
3.销毁条件变量
#include <pthread.h>
int pthread_cond_destroy(pthread_cond_t *cond);
至此我们分析出要保证生产消费者正常的完成同步与互斥,所需要的条件是
1.两个锁(分别是消费者,生产者)
2 条件变量(生产者通知消费者消费产品,消费者通知生产者生产产品)
测试代码
https://github.com/WayKwin/WD_backup/blob/master/WD/OS/Thread/p_c_model.c
测试结果
基于环形队列的消费生产者模型
和之前的生产消费者模型一样,只是条件等待条件的改变, 消费者和生产这都不能越界
例如队列满了,生产者必须等消费者
消息队列为空,消费者必须等待生产者
嘿嘿 ,win10 的paint3D还是很好玩的….
代码
https://github.com/WayKwin/WD_backup/blob/master/WD/OS/Thread/sem.c