🐶博主主页:@ᰔᩚ. 一怀明月ꦿ
❤️🔥专栏系列:线性代数,C初学者入门训练,题解C,C的使用文章,「初学」C++,linux
🔥座右铭:“不要等到什么都没有了,才下定决心去做”
🚀🚀🚀大家觉不错的话,就恳求大家点点关注,点点小爱心,指点指点🚀🚀🚀
目录
互斥锁
scp指令
线程加锁的本质
可重入VS线程安全(多执行流并发执行同一段代码时造成的数据不一致)
死锁
线程同步
生产者消费者模型
条件变量
pthread_cond_wait
pthread_cond_signal
pthread_cond_broadcast
事例:火车票抢购
互斥锁
创建全局的锁
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;//创建全局的锁,用宏去初始化
创建局部的锁
pthread_mutex_t mutex;//创建局部锁的时候不用宏初始化 pthread_mutex_init(&mutex);//初始化 pthread_mutex_destroy(&mutex);//局部的锁,不用时要销毁
scp指令
scp指令是用于在Linux系统中进行文件传输的命令,
其语法如下:
scp [选项] [源文件] [目标文件] 常用选项包括:* -r:递归复制整个目录 * -P:指定端口号 * -p:保持源文件的修改时间、访问时间和权限信息 * -q:安静模式,不显示传输进度信息 示例用法:1. 从本地复制文件到远程服务器: scp /path/to/local/file username@remotehost:/path/to/remote/directory2. 从远程服务器复制文件到本地: scp username@remotehost:/path/to/remote/file /path/to/local/directory3. 从远程服务器复制整个目录到本地: scp -r username@remotehost:/path/to/remote/directory /path/to/local/directory
线程加锁的本质
关于加锁的原则,一般原则:谁加锁,谁解锁
可重入VS线程安全(多执行流并发执行同一段代码时造成的数据不一致)
可重入函数是线程安全函数的一种
线程安全不一定是可重入的,而可重入函数则一定是线程安全的。
如果将对临界资源的访问加上锁,则这个函数是线程安全的,但如果这个重入函数若锁还未释放则会产生死锁,因此是不可重入的。
死锁
原因
1)当两个线程需要都需要两把锁,而它们每一个线程只有一把锁,此时就会导致死锁
2)当一个线程在加锁的时候,没有解锁,又去加锁,这样就会导致死锁
…….
死锁必要条件(产生死锁的时候,这四个条件一定是满足的)
互斥条件:一个资源每次只能被一个执行流使用
请求与保持条件:一个执行流因请求资源而阻塞时,对已获得的资源保持不放
不剥夺条件:一个执行流已获得的资源,在末使用完之前,不能强行剥夺
循环等待条件:若干执行流之间形成一种头尾相接的循环等待资源的关系
避免死锁
破坏死锁的四个必要条件
加锁顺序一致
避免锁未释放的场景
资源一次性分配
线程同步
线程同步的概念:
在临界资源使用安全的前提下,让多线程执行具有一定的顺序性——同步
互斥:能够保证资源的安全性
同步:能够较为充分使用我们的资源
生产者消费者模型
3种关系
生产者之间关系,互斥
消费者之间关系,互斥
生产者与消费者之间关系,互斥和同步
本质:就是用锁和条件变量,维护
2种角色
生产者,消费者——线程或者进程
1个交易场所
内存空间
生产者消费者模型提高了数据处理的能力
条件变量
创建条件变量
pthread_cond_t cond;
全局的条件变量初始化
cond=PTHREAD_COND_INITIALIZER
局部条件变量的初始化
Pthread_cond_init(&cond);
局部条件变量需要销毁
pthread_cond_destory(&cond);
pthread_cond_wait
pthread_cond_wait() 是 POSIX 线程库中的一个函数,用于线程间的条件变量同步。它需要与互斥锁(mutex)和条件变量(condition variable)一起使用。
函数原型如下:int pthread_cond_wait(pthread_cond_t* cond, pthread_mutex_t* mutex);pthread_cond_wait() 的作用是让调用线程等待条件变量的满足。在调用该函数之前, 必须先使用 pthread_mutex_lock() 锁住一个互斥锁,以确保线程安全。 当条件变量满足时,pthread_cond_wait() 函数会解锁互斥锁并使线程进入等待状态, 直到被其他线程通过 pthread_cond_signal() 或 pthread_cond_broadcast() 唤醒。
使用示例:
#include <pthread.h> // 全局互斥锁和条件变量 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cond = PTHREAD_COND_INITIALIZER; void* thread_func(void* arg) {// 获取互斥锁pthread_mutex_lock(&mutex);// 等待条件变量满足pthread_cond_wait(&cond, &mutex);// 条件变量满足后的处理// 解锁互斥锁pthread_mutex_unlock(&mutex);return NULL; } int main() {pthread_t thread;// 创建线程pthread_create(&thread, NULL, thread_func, NULL);// 在某个时刻满足条件,并通知等待的线程pthread_mutex_lock(&mutex);pthread_cond_signal(&cond);pthread_mutex_unlock(&mutex);// 等待线程结束pthread_join(thread, NULL);return 0; }
在上面的示例中,主线程通过 pthread_cond_signal() 唤醒等待的线程。当满足条件时,等待的线程会被唤醒并继续执行。注意,在调用 pthread_cond_wait() 之前必须加锁(pthread_mutex_lock()),并在条件满足后解锁(pthread_mutex_unlock())。
pthread_cond_signal
pthread_cond_signal() 是 POSIX 线程库中的一个函数,用于唤醒等待在条件变量上的一个线程。它会选择一个等待的线程,并通知该线程条件已经满足,使得该线程从等待状态恢复到运行状态。
函数原型如下:
int pthread_cond_signal(pthread_cond_t* cond); pthread_cond_signal() 的作用是发送一个信号给等待在条件变量上的某个线程, 使其从等待状态返回。如果有多个线程等待在条件变量上,那么只有其中一个线程会被唤醒, 具体哪个线程被唤醒则不确定。
pthread_cond_broadcast
pthread_cond_broadcast() 是 POSIX 线程库中的一个函数,用于广播唤醒所有等待在条件变量上的线程。当条件满足时,可以使用 pthread_cond_broadcast() 函数来唤醒所有等待在该条件变量上的线程,让它们从等待状态返回到运行状态。
函数原型如下:
int pthread_cond_broadcast(pthread_cond_t* cond); pthread_cond_broadcast() 的作用是向所有等待在条件变量上的线程发送信号, 使它们全部被唤醒。所有被唤醒的线程都会尝试重新获取互斥锁,并继续执行。
1.让线程在进行等待的时候,会自定释放锁
2.线程被唤醒的时候,是在临界区内唤醒的,当线程被唤醒的时候,线pthread_cond_wait返回的时候要重新申请并持有锁
3.当线程被唤醒的时候,重新申请并持有锁的本质是也要参与锁的竞争
单纯的互斥,能保证数据的安全,不一定合理高效!
事例:火车票抢购
test_cond
#include<iostream> #include<pthread.h> #include<unistd.h> using namespace std;pthread_cond_t cond=PTHREAD_COND_INITIALIZER;//条件变量 pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;//锁int tickets=1000;void* threadroutine(void* args) {string name=static_cast<const char*>(args);while(true){// sleep(1);pthread_mutex_lock(&mutex);//加锁if(tickets>0){cout<<name<<", get a ticket: "<<tickets--<<endl;usleep(100);}else{cout<<"没票了"<<name<<endl;pthread_cond_wait(&cond,&mutex);//让线程满足条件变量,才被唤醒//1.让线程在进行等待的时候,会自动释放锁//2.线程被唤醒的时候,是在临界区内唤醒的,当线程被唤醒的时候,线程pthread_cond_wait返回的时候//要重新申请并持有锁//3.当线程被唤醒的时候,重新申请并持有锁的本质是也要参与锁的竞争}pthread_mutex_unlock(&mutex);} }//主线程 int main() {pthread_t t1,t2,t3;pthread_create(&t1,nullptr,threadroutine,(void*)"thread - 1");pthread_create(&t2,nullptr,threadroutine,(void*)"thread - 2");pthread_create(&t3,nullptr,threadroutine,(void*)"thread - 3");sleep(5);//主线程5s之后,开始唤醒一个线程while(true){// sleep(1);// pthread_cond_signal(&cond);sleep(20);//休息20s再放一批票pthread_mutex_lock(&mutex);tickets+=1000;pthread_mutex_unlock(&mutex);pthread_cond_signal(&cond);//让一个线程被唤醒,才后这个线程在去抢票}pthread_join(t1,nullptr);pthread_join(t2,nullptr);pthread_join(t3,nullptr);return 0; }
火车票抢购,其中会同时出现多个人(线程)去抢购票,所有的抢票的过程一定要是原子的,所以需要加互斥锁。还有一个问题,在上面的抢票过程中,会在一段时间增加票的数量,但总不能让某一个人(线程)把这些票都抢光吧!所以就需要条件变量,当这次票完的时候,将这个线程阻塞住,只有被唤醒才可以继续参与抢票。
🌸🌸🌸如果大家还有不懂或者建议都可以发在评论区,我们共同探讨,共同学习,共同进步。谢谢大家! 🌸🌸🌸