当前位置: 首页 > news >正文

学习记录——day25 多线程编程 临界资源 临界区 竞态 线程的同步互斥机制(用于解决竟态)

目录

​编辑

一、多进程与多线程对比

二、 临界资源   临界区   竞态

 例1:临界资源 实现 输入输出

 例2:对临界资源 进行 减减 

例子3:临界资源抢占使用

三、线程的同步互斥机制(用于解决竟态)

3.1基本概念

3.2线程互斥

1、在C语言中,线程的互斥通过互斥锁来完成

2、互斥锁:本质上是一种临界资源,但互斥锁在同一时刻只能被一个线程使用,当一个线程试图去锁定另一个线程锁定的互斥所时,该线程会阻塞等待,直到使用互斥锁的线程解锁了该互斥锁

3、互斥锁的相关API

 4、对例3进行  互斥

3.3死锁

 3.4线程同步        

3.5线程同步 无名信号量

3.6 线程同步 条件变量


一、多进程与多线程对比

二、 临界资源   临界区   竞态

 例1:临界资源 实现 输入输出

#include <myhead.h>
#define N 2char buf[128] = "";//临界资源// 定义线程体1  使用临界资源的代码 称为临界区
void *task1(void *arg)
{while (1) // 输入信息{printf("输入:");fgets(buf, sizeof(buf), stdin);buf[strlen(buf) - 1] = 0;}
}// 定义线程体2  使用临界资源的代码 称为临界区
void *task2(void *arg)
{while (1) // 循环输出信息{usleep(500000); // 500000us  0.5s  执行一次printf("buf = %s\n", buf);bzero(buf, sizeof(buf));}
}
int main(int argc, char const *argv[])
{// 创建两个任务pthread_t tid1, tid2;if (pthread_create(&tid1, NULL, task1, NULL) != 0){printf("task1 error");return -1;}if (pthread_create(&tid2, NULL, task2, NULL) != 0){printf("task2 error");return -1;}// 主程序printf("tid1 = %#lx, tid2 = %#lx\n", tid1, tid2);// 阻塞回收线程资源pthread_join(tid1, NULL);pthread_join(tid2, NULL);return 0;
}

 例2:对临界资源 进行 减减 

#include <myhead.h>
#define N 2int num  = 520;//临界资源// 定义线程体1  使用临界资源的代码 称为临界区
void *task1(void *arg)
{while (1) // 输入信息{if (num > 0){num--;printf("task1 执行一次,剩余%d次\n",num);usleep(1000);}else{printf("task1 执行结束\n");break;}}pthread_exit(EXIT_SUCCESS);
}// 定义线程体2  使用临界资源的代码 称为临界区
void *task2(void *arg)
{while (1) // 输入信息{if (num > 0){num--;printf("task2 执行一次,剩余%d次\n",num);usleep(1000);}else{printf("task2 执行结束\n");break;}}pthread_exit(EXIT_SUCCESS);
}
int main(int argc, char const *argv[])
{// 创建两个任务pthread_t tid1, tid2;if (pthread_create(&tid1, NULL, task1, NULL) != 0){printf("task1 error");return -1;}if (pthread_create(&tid2, NULL, task2, NULL) != 0){printf("task2 error");return -1;}// 主程序printf("tid1 = %#lx, tid2 = %#lx\n", tid1, tid2);// 阻塞回收线程资源pthread_join(tid1, NULL);pthread_join(tid2, NULL);return 0;
}

例子3:临界资源抢占使用

#include <myhead.h>
#define N 2int num  = 520;//临界资源// 定义线程体1  使用临界资源的函数 称为临界区
void *task1(void *arg)
{while (1) // 输入信息{if (num > 0){num--;printf("task1 执行一次,剩余%d次\n",num);usleep(1000);}else{printf("task1 执行结束\n");break;}}pthread_exit(EXIT_SUCCESS);
}// 定义线程体2  使用临界资源的函数 称为临界区
void *task2(void *arg)
{while (1) // 输入信息{if (num > 0){num--;printf("task2 执行一次,剩余%d次\n",num);usleep(1000);}else{printf("task2 执行结束\n");break;}}pthread_exit(EXIT_SUCCESS);
}// 定义线程体1  使用临界资源的函数 称为临界区
void *task3(void *arg)
{while (1) // 输入信息{if (num > 0){num--;printf("task3 执行一次,剩余%d次\n",num);usleep(1000);}else{printf("task3 执行结束\n");break;}}pthread_exit(EXIT_SUCCESS);
}
int main(int argc, char const *argv[])
{// 创建三个任务pthread_t tid1, tid2,tid3;if (pthread_create(&tid1, NULL, task1, NULL) != 0){printf("task1 error");return -1;}if (pthread_create(&tid2, NULL, task2, NULL) != 0){printf("task2 error");return -1;}if (pthread_create(&tid3, NULL, task3, NULL) != 0){printf("task2 error");return -1;}// 主程序printf("tid1 = %#lx, tid2 = %#lx\n", tid1, tid2);// 阻塞回收线程资源pthread_join(tid1, NULL);pthread_join(tid2, NULL);pthread_join(tid3, NULL);return 0;
}

        由于多个线程共同使用进程的资源,导致,线程在操作上容易出现不安全的状态

        对于例3 减减 含有多步操作 相对耗时 在多个线程对临界资源抢占使用时,会出现某一个线程的 减减 未结束另一个线程的 开始执行,就会导致数据出错。

        该现象称为 竞态

三、线程的同步互斥机制(用于解决竟态)

        如上例3所示,当其中一个线程正在访问全局变量时,可能会出现时间片用完的情况,另一个线程将数据进行更改后,再执行 该线程时,导致数据的不一致。这种现象称竞态,为了解决竞态,引入了同步互斥机制

3.1基本概念

1)竟态:同一个进程的多个线程在访问临界资源时,会出现抢占的现象,导致线程中的数据错误的现象称为竞态

2)临界资源:多个线程共同访问的数据称为临界资源,可以是全局变量、堆区数据、外部文件

3)临界区:访问临界资源的代码段称为临界区

4)粒度:临界区的大小

5)同步:表示多个任务有先后顺序的执行

6)互斥:表示在访问临界区时,同一时刻只能有一个任务,当有任务在访问临界区时,其他任务只能等待

3.2线程互斥

1、在C语言中,线程的互斥通过互斥锁来完成

2、互斥锁:本质上是一种临界资源,但互斥锁在同一时刻只能被一个线程使用,当一个线程试图去锁定另一个线程锁定的互斥所时,该线程会阻塞等待,直到使用互斥锁的线程解锁了该互斥锁

3、互斥锁的相关API

       #include <pthread.h>
       1、创建互斥锁:只需要定义一个pthread_mutex_t类型的变量,就创建了一个互斥锁

       pthread_mutex_t fastmutex = PTHREAD_MUTEX_INITIALIZER;           //静态初始化一个互斥锁

       2、初始化互斥锁

       int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr);
       功能:初始化一个互斥锁
       参数1:互斥锁变量的地址
       参数2:互斥锁的属性,一般填NULL,使用系统默认提供的属性
       返回值:总是成功,不会失败(成功返回0)
        
       3、获取锁资源

       int pthread_mutex_lock(pthread_mutex_t *mutex);
       功能:某个线程调用该函数表示获取锁资源(阻塞等待)
       参数:互斥锁的地址
       返回值:成功返回0,失败返回一个错误码
       
       4、释放锁资源

        int pthread_mutex_unlock(pthread_mutex_t *mutex);
       功能:将线程中的锁资源释放
       参数:互斥锁的地址
       返回值:成功返回0,失败返回一个错误码
       
        5、销毁锁资源
       int pthread_mutex_destroy(pthread_mutex_t *mutex);
       功能:销毁程序中的锁资源
       参数:互斥锁地址        

 4、对例3进行  互斥

#include <myhead.h>
#define N 2int num = 520; // 临界资源// 创建一个互斥锁
pthread_mutex_t mutex;// 定义线程体1  使用临界资源的代码 称为临界区
void *task1(void *arg)
{while (1) // 输入信息{// 上锁  获取锁资源pthread_mutex_lock(&mutex);if (num > 0){num--;printf("task1 执行一次,剩余%d次\n", num);usleep(1000);}else{printf("task1 执行结束\n");// 解锁 释放锁资源pthread_mutex_unlock(&mutex); // 结束前解锁 避免死锁break;}// 解锁 释放锁资源pthread_mutex_unlock(&mutex);}pthread_exit(EXIT_SUCCESS);
}// 定义线程体2  使用临界资源的代码 称为临界区
void *task2(void *arg)
{while (1) // 输入信息{// 上锁  获取锁资源pthread_mutex_lock(&mutex);if (num > 0){num--;printf("task2 执行一次,剩余%d次\n", num);usleep(1000);}else{printf("task2 执行结束\n");// 解锁 释放锁资源pthread_mutex_unlock(&mutex); // 避免死锁break;}// 解锁 释放锁资源pthread_mutex_unlock(&mutex);}pthread_exit(EXIT_SUCCESS);
}// 定义线程体3  使用临界资源的函数 称为临界区
void *task3(void *arg)
{while (1) // 输入信息{// 上锁  获取锁资源pthread_mutex_lock(&mutex);if (num > 0){num--;printf("task3 执行一次,剩余%d次\n", num);usleep(1000);}else{printf("task3 执行结束\n");// 解锁 释放锁资源pthread_mutex_unlock(&mutex); // 避免死锁break;}// 解锁 释放锁资源pthread_mutex_unlock(&mutex);}pthread_exit(EXIT_SUCCESS);
}
int main(int argc, char const *argv[])
{//初始化锁pthread_mutex_init(&mutex, NULL);// 创建三个任务pthread_t tid1, tid2, tid3;if (pthread_create(&tid1, NULL, task1, NULL) != 0){printf("task1 error");return -1;}if (pthread_create(&tid2, NULL, task2, NULL) != 0){printf("task2 error");return -1;}if (pthread_create(&tid3, NULL, task3, NULL) != 0){printf("task2 error");return -1;}// 主程序printf("tid1 = %#lx, tid2 = %#lx\n", tid1, tid2);// 阻塞回收线程资源pthread_join(tid1, NULL);pthread_join(tid2, NULL);pthread_join(tid3, NULL);// 销毁锁资源pthread_mutex_destroy(&mutex);return 0;
}

3.3死锁

1、概念:在多线程编程中,死锁是一种情况,其中两个或多个线程被永久阻塞,因为每个线程都在等待其他线程释放它们需要的资源。在C语言中,这通常涉及互斥锁(mutexes),当多个互斥锁被不同的线程以不同的顺序获取时,很容易发生死锁。

2、产生条件:

1) 互斥条件:资源不能被多个线程共享,只能被一个线程在任一时刻所使用。
2) 持有和等待条件:一个线程至少持有一个资源,并且正在等待获取一个当前被其他线程持有的资源。
3.)不可抢占条件:资源不能被强制从一个线程抢占到另一个线程,线程必须自愿释放它的资源。
4.)循环等待条件:存在一个线程(或多个线程)的集合{P1, P2, ..., Pn},其中P1正在等待P2持有的资源,P2正在等待P3持有的资源,依此类推,直至Pn正在等待P1持有的资源。

3、例4:死锁示例

#include <pthread.h>
#include <stdio.h>pthread_mutex_t lock1, lock2;void* thread1(void* arg) {pthread_mutex_lock(&lock1);sleep(1); // 确保线程2能锁住lock2pthread_mutex_lock(&lock2);printf("Thread 1\n");pthread_mutex_unlock(&lock2);pthread_mutex_unlock(&lock1);return NULL;
}void* thread2(void* arg) {pthread_mutex_lock(&lock2);sleep(1); // 确保线程1能锁住lock1pthread_mutex_lock(&lock1);printf("Thread 2\n");pthread_mutex_unlock(&lock1);pthread_mutex_unlock(&lock2);return NULL;
}int main() {pthread_t t1, t2;pthread_mutex_init(&lock1, NULL);pthread_mutex_init(&lock2, NULL);pthread_create(&t1, NULL, thread1, NULL);pthread_create(&t2, NULL, thread2, NULL);pthread_join(t1, NULL);pthread_join(t2, NULL);pthread_mutex_destroy(&lock1);pthread_mutex_destroy(&lock2);return 0;
}

4、避免死锁的策略:

1.)避免持有和等待:尽可能让线程在开始执行前一次性获取所有必需的资源。
2.)资源排序:规定一个全局顺序来获取资源,并且强制所有线程按这个顺序获取资源。
3.)使用超时:在尝试获取资源时使用超时机制,这样线程在等待过长时间后可以放弃,回退,并重新尝试。
4.)检测死锁并恢复:运行时检测死锁的存在,一旦检测到死锁,采取措施(如终止线程或回滚操作)来解决。

 3.4线程同步        

1、多个线程任务有顺序的执行,由于多个任务有顺序的执行了,那么在同一时刻,对临界资源的访问就只一个线程

2、线程同步文件的经典问题是:生产者消费者问题

        对于该问题而言,需要先执行生产者任务,然后执行消费者任务

3、对于线程同步问题,有两种机制来完成:无名信号量、条件变量

3.5线程同步 无名信号量

1、无名信号量本质上也是一个特殊的临界资源

2、无名信号量中维护了一个value值,该值表示能够申请的资源个数,当该值为0时,申请资源的线程将处于阻塞,直到其他线程将该无名信号量中的value值增加到大于0时即可

3、无名信号量API

1、创建无名信号量:只需要定义一个 sem_t 类型的变量,就创建了一个无名信号量
    sem_t  sem;
2、初始化无名信号量
           #include <semaphore.h>

       int sem_init(sem_t *sem, int pshared, unsigned int value);
       功能:完成对无名信号量的初始化工作
       参数1:要被初始化的无名信号量地址
       参数2:无名信号量适用情况
           0:表示多线程之间
           非0:表示多进程间同步
        参数3:无名信号量的资源初始值
        返回值:成功返回0,失败返回-1并置位错误码

3、申请资源:P操作,将资源减1操作
           #include <semaphore.h>

       int sem_wait(sem_t *sem);
       功能:申请无名信号量中的资源,使得该信号量中的value-1
       参数:无名信号量地址
       返回值:成功返回0,失败返回-1并置位错误码

4、释放资源:V操作,将资源加1操作
               #include <semaphore.h>

       int sem_post(sem_t *sem);
       功能:将无名信号量中的资源加1操作
       参数:无名信号量地址
       返回值:成功返回0,失败返回-1并置位错误码

5、销毁无名信号量
       #include <semaphore.h>

       int sem_destroy(sem_t *sem);
       功能:销毁一个无名信号量
       参数:无名信号量地址
       返回值:成功返回0,失败返回-1并置位错误码

 4、同步  无名信号量 示例

未 使用 无名信号量

#include <myhead.h>//创建生产者线程
void * task1(void *arg)
{int num = 5;while (num--){printf("%#lx:执行一次生产\n",pthread_self());sleep(1);}pthread_exit(EXIT_SUCCESS);
}//创建消费者线程
void * task2(void *arg)
{int num = 5;while (num--){printf("%#lx:执行一次消费\n",pthread_self());}pthread_exit(EXIT_SUCCESS);
}
int main(int argc, char const *argv[])
{pthread_t tid1, tid2;if (pthread_create(&tid1, NULL, task1, NULL) != 0){printf("task1 error");return -1;}if (pthread_create(&tid2, NULL, task2, NULL) != 0){printf("task1 error");return -1;}pthread_join(tid2, NULL);pthread_join(tid1, NULL);return 0;
}

 

 使用 无名信号量

#include <myhead.h>//1、创建无名学号量
sem_t sem;//创建生产者线程
void * task1(void *arg)
{int num = 5;while (num--){printf("%#lx:执行一次生产\n",pthread_self());//4、释放资源 无名信号量资源加1 允许消费者a线程执行sem_post(&sem);}pthread_exit(EXIT_SUCCESS);
}//创建消费者线程
void * task2(void *arg)
{int num = 5;while (num--){//3、申请资源sem_wait(&sem); //阻塞等待  生产者线程释放 无名信号量资源//当无名信号量资源 为1时 执行 减1//因为 无名信号量 初始资源为0  即便先执行消费者线程也会被阻塞printf("%#lx:执行一次消费\n",pthread_self());}pthread_exit(EXIT_SUCCESS);
}
int main(int argc, char const *argv[])
{//2、初始化无名信号量sem_init(&sem,0,0);//第一个0   表示同步用于多线程间//第二e个0  表示无名信号量初始资源为0pthread_t tid1, tid2;if (pthread_create(&tid1, NULL, task1, NULL) != 0){printf("task1 error");return -1;}if (pthread_create(&tid2, NULL, task2, NULL) != 0){printf("task1 error");return -1;}pthread_join(tid2, NULL);pthread_join(tid1, NULL);//5、销毁无名信号量sem_destroy(&sem);return 0;
}

3.6 线程同步 条件变量

1、条件变量的本质也是一个特殊的临界资源

2、条件变量中维护了一个队列,想要执行的消费者线程,需要先进入等待队列中,等生产者线程进行唤醒后,依次执行。这样就可以做到一个生产者和多个消费者之间的同步,但是消费者和消费者之间在进入等待队列这件事上是互斥的。

3、条件变量的API

1)创建条件变量
    只需要定义一个pthread_cond_t类型的变量,就创建了一个条件变量
    pthread_cond_t  cond;

2)初始化条件变量
       int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr);
       功能:初始化一个条件变量
       参数1:条件变量的地址
       参数2:条件变量的属性,一般填NULL
       返回值:     成功返回0,失败返回非0错误码
       

3)将消费者线程放入到等待队列中       

       int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
       功能:消费者线程进入等待队列中
       参数1:条件变量的地址
       参数2:互斥锁的地址:因为多个消费者线程在进入等待队列上是竞态的
       返回值:     成功返回0,失败返回非0错误码

4)唤醒消费者线程                                

       int pthread_cond_signal(pthread_cond_t *cond);
       功能:唤醒等待队列中的第一个消费者线程
       参数:条件变量的地址
       返回值: 成功返回0,失败返回非0错误码       

       

       int pthread_cond_broadcast(pthread_cond_t *cond);
       功能:唤醒所有等待队列中的消费者线程
       参数:条件变量的地址
       返回值: 成功返回0,失败返回非0错误码
       

    
5)销毁条件变量           
        int pthread_cond_destroy(pthread_cond_t *cond);
        功能:销毁一个条件变量
        参数:条件变量的地址
        返回值: 成功返回0,失败返回非0错误码

 4、条件变量 示例

#include <myhead.h>//1、定义一个条件变量
pthread_cond_t cond;//11、创建互斥锁
pthread_mutex_t mutex;// 创建生产者线程
void *task1(void *arg)
{// int num = 5;// while (num--)// {//     sleep(1);//     printf("%#lx:执行一次生产\n", pthread_self());//     //4、唤醒消费者线程(单个)//     pthread_cond_signal(&cond);// }sleep(3);printf("%#lx:执行5次生产\n", pthread_self());pthread_cond_broadcast(&cond);//4、唤醒消费者线程(全部)pthread_exit(EXIT_SUCCESS);
}// 创建消费者线程
void *task2(void *arg)
{//33、获取互斥锁pthread_mutex_lock(&mutex);//3、请求进入等待队列pthread_cond_wait(&cond,&mutex);printf("%#lx:执行一次消费\n", pthread_self());//44、释放互斥锁pthread_mutex_unlock(&mutex);pthread_exit(EXIT_SUCCESS);
}
int main(int argc, char const *argv[])
{//2、初始化统计变量pthread_cond_init(&cond,NULL);//22、初始化互斥锁pthread_mutex_init(&mutex,NULL);pthread_t tid1, tid2, tid3, tid4, tid5, tid6;if (pthread_create(&tid1, NULL, task1, NULL) != 0){printf("task1 error");return -1;}if (pthread_create(&tid2, NULL, task2, NULL) != 0){printf("task1 error");return -1;}if (pthread_create(&tid3, NULL, task2, NULL) != 0){printf("task1 error");return -1;}if (pthread_create(&tid4, NULL, task2, NULL) != 0){printf("task1 error");return -1;}if (pthread_create(&tid5, NULL, task2, NULL) != 0){printf("task1 error");return -1;}if (pthread_create(&tid6, NULL, task2, NULL) != 0){printf("task1 error");return -1;}//输出每个线程的线程号printf("tid2=%#lx tid3=%#lx tid4=%#lx tid5=%#lx tid6=%#lx \n",tid2,tid3,tid4,tid5,tid6);pthread_join(tid2, NULL);pthread_join(tid1, NULL);pthread_join(tid3, NULL);pthread_join(tid4, NULL);pthread_join(tid5, NULL);pthread_join(tid6, NULL);//5、销毁条件变量pthread_cond_destroy(&cond);//55、销毁锁资源pthread_mutex_destroy(&mutex);return 0;
}

 

相关文章:

学习记录——day25 多线程编程 临界资源 临界区 竞态 线程的同步互斥机制(用于解决竟态)

目录 ​编辑 一、多进程与多线程对比 二、 临界资源 临界区 竞态 例1&#xff1a;临界资源 实现 输入输出 例2&#xff1a;对临界资源 进行 减减 例子3&#xff1a;临界资源抢占使用 三、线程的同步互斥机制&#xff08;用于解决竟态&#xff09; 3.1基本概念 3.2线…...

[RK3566]linux下使用upgrade_tool报错

linux下使用upgrade_tool报错Creating Comm Object failed! Rockusb>uf /home/zhuhongxi/RK3566_AOSP_SDK/rockdev/Image-rk3566_tspi/update.img Loading firmware... Support Type:RK3568 FW Ver:b.0.00 FW Time:2024-08-03 12:00:09 Loader ver:1.01 Loader Time:…...

系统架构师(每日一练13)

每日一练 答案与解析 1.应用系统构建中可以采用多种不同的技术&#xff0c;()可以将软件某种形式的描述转换为更高级的抽象表现形式&#xff0c;而利用这些获取的信息&#xff0c;()能够对现有系统进行修改或重构&#xff0c;从而产生系统的一个新版本。答案与解析 问题1 A.逆…...

Error: No module factory available for dependency type: CssDependency

本篇主要用来记录VUE打包的问题点&#xff0c;今天使用npm run build:prod 打包VUE出现如下问题&#xff1a; Error: No module factory available for dependency type: CssDependency 因为测试和预发布都挺正常的&#xff0c;正式环境竟然出问题&#xff0c;废话不多说&…...

【langchain学习】使用Langchain生成多视角查询

使用Langchain生成多视角查询 导入所需库&#xff1a; from langchain.prompts import ChatPromptTemplate from langchain_core.output_parsers import StrOutputParser from langchain_core.runnables import RunnablePassthrough from config import llm设置提示模板&#x…...

ASPCMS 漏洞详细教程

一.后台修改配置文件拿shell 登录后台 如下操作 保存并抓包 将slideTextStatus的值修改为1%25><%25Eval(Request(chr(65)))25><%25 放包&#xff08;连接密码是a&#xff09; 然后用工具连接 成功连接...

二维码生成原理及解码原理

☝☝☝二维码配图 二维码 二维码&#xff08;Quick Response Code&#xff0c;简称QR码&#xff09;是一种广泛使用的二维条形码技术&#xff0c;由日本公司Denso Wave在1994年开发。二维码能有效地存储和传递信息&#xff0c;广泛应用于商品追溯、支付、广告等多个领域。二维…...

云计算实训20——mysql数据库安装及应用(增、删、改、查)

一、mysql安装基本步骤 1.下载安装包 wget https://downloads.mysql.com/archives/get/p/23/file/mysql-8.0.33-1.el7.x86_64.rpm-bundle.tar 2.解压 tar -xf mysql-8.0.33-1.el7.x86_64.rpm-bundle.tar 3.卸载mariadb yum -y remove mariadb 查看解压后的包 [rootmysq…...

24年电赛——自动行驶小车(H题)基于 CCS Theia -陀螺仪 JY60 代码移植到 MSPM0G3507(附代码)

前言 只要搞懂 M0 的代码结构和 CCS 的图形化配置方法&#xff0c;代码移植就会变的很简单。因为本次电赛的需要&#xff0c;正好陀螺仪部分代码的移植是我完成的。&#xff08;末尾附全部代码&#xff09; 一、JY60 陀螺仪 JY60特点 1.模块集成高精度的陀螺仪、加速度计&…...

数组的增删查查改

1、增 1.Cpp #include <iostream> using namespace std; #include "add.h"int main() {//初始化数组int arr[5];//前四个元素为1&#xff0c;2&#xff0c;3&#xff0c;4for (int i 0; i < 4; i){arr[i] i1;}//数组第5个赋值为100arr[4] 100;for (int…...

设计模式——动态代理

设计模式——动态代理 动态代理的基本概念动态代理的实现步骤总结 在Java中&#xff0c;动态代理是一种强大的机制&#xff0c;它允许在运行时创建一个代理对象&#xff0c;这个代理对象可以代表另一个实际对象&#xff0c;它允许你在不直接操作原始对象的情况下&#xff0c;通…...

vue(element-ui组件) 的this.$notify的具体使用

getNotify() {this.noClose();let message "";message this.itemData.map((ele) > {const text "任务" ele.title "新增" ele.num "条言论";return this.$createElement("el-tooltip",{props: {content: text,pla…...

c++ - 模拟实现set、map

文章目录 前言一、set模拟实现二、map模拟实现 前言 在C标准库中&#xff0c;std::set 和 std::map都是非常常用的容器&#xff0c;它们提供了基于键值对的存储和快速查找能力。然而&#xff0c;关于它们的底层实现&#xff0c;C标准并没有强制规定具体的数据结构&#xff0c;只…...

计算机网络-PIM协议基础概念

一、PIM基础概念 组播网络回顾&#xff1a; 组播网络从网络结构上大体可以分为三个部分&#xff1a; 源端网络&#xff1a;将组播源产生的组播数据发送至组播网络。 组播转发网络&#xff1a;形成无环的组播转发路径&#xff0c;该转发路径也被称为组播分发树&#xff08;Multi…...

优化PyCharm:让IDE响应速度飞起来

优化PyCharm&#xff1a;让IDE响应速度飞起来 PyCharm&#xff0c;作为一款功能强大的集成开发环境&#xff08;IDE&#xff09;&#xff0c;在提供丰富功能的同时&#xff0c;有时也会出现响应慢的问题。这不仅影响开发效率&#xff0c;还可能打击开发者的积极性。本文将详细…...

对象转化为String,String转化为对象

title: 对象转化为string&#xff0c;string转化为对象 date: 2024-08-02 11:50:40 tags: javascript const obj { uname:haha, age:18,gender:女} //将对象转换成string JSON.stringify(obj) //取成一个对象&#xff0c;将字符串传化为对象 JSON.parse(obj)常用领域在localst…...

SolverLearner:提升大模型在高度归纳推理的复杂任务性能,使其能够在较少的人为干预下自主学习和适应

SolverLearner&#xff1a;提升大模型在高度归纳推理的复杂任务性能&#xff0c;使其能够在较少的人为干预下自主学习和适应 提出背景归纳推理&#xff08;Inductive Reasoning&#xff09;演绎推理&#xff08;Deductive Reasoning&#xff09;反事实推理&#xff08;Counterf…...

PHP智能问诊导诊平台-计算机毕业设计源码75056

摘 要 智能问诊导诊平台作为一种智能化医疗服务工具&#xff0c;利用PHP语言开发&#xff0c;旨在为用户提供便捷的在线问诊和导诊服务。该平台集成了智能算法和医疗数据&#xff0c;实现了智能化的病情诊断和治疗建议&#xff0c;帮助用户更快速地获取医疗信息和建议。用户可…...

数据结构初阶(c语言)-排序算法

数据结构初阶我们需要了解掌握的几种排序算法(除了直接选择排序&#xff0c;这个原因我们后面介绍的时候会解释)如下&#xff1a; 其中的堆排序与冒泡排序我们在之前的文章中已经详细介绍过并对堆排序进行了一定的复杂度分析&#xff0c;所以这里我们不再过多介绍。 一&#x…...

网络云相册实现--nodejs后端+vue3前端

目录 主页面 功能简介 系统简介 api 数据库表结构 代码目录 运行命令 主要代码 server apis.js encry.js mysql.js upload.js client3 index.js 完整代码 主页面 功能简介 多用户系统&#xff0c;用户可以在系统中注册、登录及管理自己的账号、相册及照片。 每…...

【JS】Object.defineProperty与Proxy

一、Object.defineProperty 这里只是简单描述&#xff0c;具体请看另一篇文章&#xff1a;Object.defineProperty。 Object.defineProperty 是 JavaScript 中用于定义或修改对象属性的功能强大的方法。它可以精确地控制属性的行为&#xff0c;如是否可枚举、可配置、可写等。…...

《计算机网络》(第8版)第8章 互联网上的音频/视频服务 复习笔记

第 8 章 互联网上的音频/视频服务 一、概述 1 多媒体信息的特点 多媒体信息&#xff08;包括声音和图像信息&#xff09;最主要的两个特点如下&#xff1a; &#xff08;1&#xff09;多媒体信息的信息量往往很大&#xff1b; &#xff08;2&#xff09;在传输多媒体数据时&a…...

linux进程控制——进程替换——exec函数接口

前言&#xff1a; 本节内容进入linux进程控制板块的最后一个知识点——进程替换。 通过本板块的学习&#xff0c; 我们了解了进程的基本控制方法——进程创建&#xff0c; 进程退出&#xff0c; 进程终止&#xff0c; 进程替换。 进程控制章节和上一节进程概念板块都是在谈进程…...

Apache解析漏洞~CVE-2017-15715漏洞分析

Apache解析漏洞 漏洞原理 # Apache HTTPD 支持一个文件拥有多个后缀&#xff0c;并为不同后缀执行不同的指令。比如如下配置文件&#xff1a; AddType text/html .html AddLanguage zh-CN .cn# 其给 .html 后缀增加了 media-type &#xff0c;值为 text/html &#xff1b;给 …...

Xilinx管脚验证流程及常见问题

1 流程 1.1 新建I/O Planning Project I/O Planning Project中可以不需要RTL的top层.v代码&#xff0c;仅图形化界面即可配置管脚约束XDC文件的生成&#xff1a; Create I/O Ports&#xff1a; 导出XDC文件和自动生成的top_interface.v文件&#xff1a; 1.2 新建test Project …...

格雷厄姆的《聪明的投资者》被誉为“投资圣经”

本杰明格雷厄姆的《聪明的投资者》&#xff08;The Intelligent Investor: A Book of Practical Counsel&#xff09;是投资领域的一部经典之作&#xff0c;被誉为“投资圣经”。以下是对该书的详细解析&#xff1a; 一、书籍基本信息 书名&#xff1a;《聪明的投资者》&…...

TypeScript声明文件

TypeScript声明文件 在JavaScript的生态系统中&#xff0c;随着项目的复杂度和规模不断增加&#xff0c;开发者对于类型安全和代码质量的追求也日益增长。TypeScript&#xff0c;作为JavaScript的一个超集&#xff0c;通过添加静态类型检查和ES6等新特性支持&#xff0c;极大地…...

.NET_WPF_使用Livecharts数据绑定图表

相关概念 LiveCharts 是一个开源的图表库&#xff0c;适用于多种 .NET 平台&#xff0c;包括 WPF、UWP、WinForms 等。LiveCharts 通过数据绑定与 MVVM 模式兼容&#xff0c;使得视图模型可以直接控制图表的显示&#xff0c;无需直接操作 UI 元素。这使得代码更加模块化&#x…...

一句JS代码,实现随机颜色的生成

今天我们只用 一句JS代码&#xff0c;实现随机颜色的生成&#xff0c;首先看一下效果&#xff1a; 每次刷新浏览器背景颜色都不一样 实现此效果的JS函数 &#xff1a; let randomColor () > ...: 定义一个箭头函数randomColor&#xff0c;用于生成一个随机颜色。 Math.ra…...

校园抢课助手【7】-抢课接口限流

在上一节中&#xff0c;该接口已经接受过风控的处理&#xff0c;过滤掉了机器人脚本请求&#xff0c;剩下都是人为的下单请求。为了防止用户短时间内高频率点击抢课链接&#xff0c;海量请求造成服务器过载&#xff0c;这里使用接口限流算法。 先介绍下几种常用的接口限流策略…...

小企业网站建设的小知识/百度贴吧网页版

很久了一直思考程序员应该先学哪门编程语言&#xff0c;必须掌握哪些编程语言&#xff0c;如何一个学习顺序。正好看到金老师也在研究第一门编程语言选谁(http://blog.csdn.net/bitfan/article/details/7939691)&#xff0c;在此也表达一下个人看法。 金老师说到的第一门编程语…...

商城网站开发项目文档/网络排名优化软件

硬件平台:STM32F29IG (阿波罗F4开发板) IIC管脚 :I2C2(PH4:SCL PH5:SDA) 1.使用STM32CubeMX 获取初始代码 2.(HAL)基础函数 IIC分为三种模式: 阻塞,中断,DMA /* IO operation functions ****************************************************/ /******* Blocking mode:…...

重庆哪些网站推广公司/网站优化排名公司哪家好

1. 首先安装插件Alibaba Cloud Toolkit 安装成后&#xff0c;会提示重启IDEA。 2. 打开插件工具 Tool >> Alibaba Cloud >> Deploy to Host 配置远程服务器账号密码 首次打开显示如下&#xff0c;需要添加Host&#xff0c;点击后面的 Add Host 添加完成。再次打开…...

html企业网站开发/软件开发公司有哪些

计算机网络原理的基本概念&#x1f50e;IP地址概念格式特殊IP地址&#x1f50e;端口号概念格式注意&#x1f50e;关于IP地址与端口号&#x1f50e;协议概念协议的三要素协议的作用&#x1f50e;协议分层协议分层的作用&#x1f50e;OSI 模型&#x1f50e;网络设备所在分层&…...

个人网站怎么进后台/培训教育机构

1.下载VMware虚拟机 https://www.vmware.com/cn/products/workstation/workstation-evaluation.html 永久激活12位序列号&#xff1a;5A02H-AU243-TZJ49-GTC7K-3C61N 2.下载linux系统 https://www.linux.org 3.创建一个虚拟机&#xff0c;选择下载好的linux系统&#xff0c;我这…...

wordpress提示收藏夹/惠州网站排名提升

题记&#xff1a;本文根据我自己的一点经验&#xff0c;讨论了Mysql服务器优化中两个非常重要的参数&#xff0c;分别是table_cache&#xff0c;key_buffer_size。table_cache指示表高速缓存的大小。当Mysql访问一个表时&#xff0c;如果在Mysql表缓冲区中还有空间&#xff0c;…...