赞
踩
举一个例子:
学生去超市消费的时候,与厂家生产的时候,两者互不相冲突。
生产的过程与消费的过程 – 解耦
临时的保存产品的场所(超时) – 缓冲区
模型总结“321”原则:
只要我们想写生产消费模型,我们本质工作其实就是维护321原则!
特点:
举例:
我们以前:main函数获取用户输入,然后调用fun函数,fun函数执行,打印结果。这是一个串行的流程,现在我们对应生产者消费者模型:
由于上述的原因,我们不能仅靠锁来去实现线程互斥。
什么是条件变量:
感性认识条件变量:
模拟一个面试流程:
1.假如我们一堆人都要到一家公司面试,但是这个公司的HR组织的不行,每次面试都是一堆人举手来竞争面试机会,都说要自己先来,而HR也是看谁顺眼就让他进去面试 – 一份共享资源被多线程并发式的竞争
2.同样是面试,而HR组织的好,说要面试必须要到等待区等待,按照排队顺序来:(这个等待区就是一个条件变量)
当条件不满足的时候,我们线程必须去某些定义好的条件变量上进行等待!
#include <iostream> #include <string> #include <unistd.h> #include <pthread.h> int tickets = 1000; pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cond = PTHREAD_COND_INITIALIZER; void *start_routine(void *args) { std::string name = static_cast<const char *>(args); while (true) { pthread_mutex_lock(&mutex); pthread_cond_wait(&cond, &mutex); // 为什么要有mutex,后面就说 // 判断暂时省略 std::cout << name << " -> " << tickets << std::endl; tickets--; pthread_mutex_unlock(&mutex); } } int main() { // 通过条件变量控制线程的执行 pthread_t t[5]; for (int i = 0; i < 5; i++) { char *name = new char[64]; snprintf(name, 64, "thread %d", i + 1); pthread_create(t+i, nullptr, start_routine, name); } while (true) { sleep(1); pthread_cond_signal(&cond); //pthread_cond_broadcast(&cond); std::cout << "main thread wakeup one thread..." << std::endl; } for (int i = 0; i < 5; i++) { pthread_join(t[i], nullptr); } return 0; }
我们可以发现进程按照一定的顺序在执行
POSIX
信号量和SystemV
信号量作用相同,都是用于同步操作,达到无冲突的访问共享资源目的。 但POSIX可以用于线程间同步。
初始化信号量
#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);
参数:
pshared:0表示线程间共享,非零表示进程间共享
value:信号量初始值
销毁信号量
int sem_destroy(sem_t *sem);
等待信号量
功能:等待信号量,会将信号量的值减1
int sem_wait(sem_t *sem); //P()
发布信号量
功能:发布信号量,表示资源使用完毕,可以归还资源了。将信号量值加1。
int sem_post(sem_t *sem);//V()
场景一:你喊你的朋友一起去吃饭,你的朋友说等他一会就来,在等的期间你每隔一会就打电话问他来没来 – 自旋
场景二:你喊你的朋友一起去吃饭,你的朋友说等他一会就来,你不想就只在原地等,你走路去学校网吧上网,走路去的过程叫做挂起,在网吧上网叫做等待,你朋友跟你打电话说他已经来了,然后你回学校这叫做唤醒。-- 挂起等待
是什么决定了最终的等待方式?
等待的时间问题。已经被申请的临界资源决定了其他线程要等待,一个成功申请临界资源的线程在临界区内要待多少时间,这个时间长短就决定了我们使用哪种方式:(阻塞等待/自旋)。时间的长短如何定义?都是用分别测试效果。
int pthread_spin_lock(pthread_spinlock_t *lock);
int pthread_spin_trylock(pthread_spinlock_t *lock);
int pthread_spin_destroy(pthread_spinlock_t *lock);
int pthread_spin_init(pthread_spinlock_t *lock, int pshared);
int pthread_spin_unlock(pthread_spinlock_t *lock);
在编写多线程的时候,有一种情况是十分常见的。那就是,有些公共数据修改的机会比较少。相比较改写,它们读的机会反而高的多。通常而言,在读的过程中,往往伴随着查找的操作,中间耗时很长。给这种代码段加锁,会极大地降低我们程序的效率。那么有没有一种方法,可以专门处理这种多读少写的情况呢? 有,那就是读写锁。
场景:比如在以前学校的黑板报,画黑板报的为写者,写者与写者之间是互斥关系(你正在写字,他不能把你写的字擦了画画),而观看的同学是读者,读者与读者之间不存在什么关系(黑板报画好了,我们都是一起看的,不存在先来就先看其余的蒙着眼睛不准看)。
读者写者模型与生产者消费者模型本质区别是:消费者会拿走数据而读者不会。
读者写者:写者之间 – 互斥 、读写者 – 互斥/同步 、读者之间 – 没关系
读者写者模型适用场景:一次发布,很长时间不做修改,大部分时间都是被读取的(大部分时间都是被读写,少量的时间在进行写入)
设置读写优先
int pthread_rwlockattr_setkind_np(pthread_rwlockattr_t *attr, int pref);
pref 共有 3 种选择
PTHREAD_RWLOCK_PREFER_READER_NP (默认设置) 读者优先,可能会导致写者饥饿情况
PTHREAD_RWLOCK_PREFER_WRITER_NP 写者优先,目前有 BUG,导致表现行为和
PTHREAD_RWLOCK_PREFER_READER_NP 一致
PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP 写者优先,但写者不能递归加锁
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,
const pthread_rwlockattr_t *restrict attr);
读者加锁:
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
写者加锁:
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
统一解锁:
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
如有错误或者不清楚的地方欢迎私信或者评论指出
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/82870
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。