Linux系统编程——线程的学习

学习参考博文:
Linux多线程编程初探

Linux系统编程学习相关博文

  1. Linux系统编程——文件编程的学习
  2. Linux系统编程——进程的学习
  3. Linux系统编程——进程间通信的学习
  4. Linux系统编程——网络编程的学习

Linux系统编程——线程的学习

  • 一、概述
    • 1. 进程与线程的区别
    • 2. 使用线程的理由
    • 3. 互斥量
    • 4. 条件变量
  • 二、线程API
  • 三、API介绍
    • 1. pthread_creat函数
    • 2. pthread_exit函数
    • 3. pthread_join函数
    • 4. pthread_self函数
    • 5. pthread_mutex_inti函数
    • 6. pthread_mutex_destroy函数
    • 7. pthread_mutex_lock函数
    • 8. pthread_mutex_unlock函数
    • 9. pthread_cond_init函数
    • 10. pthread_cond_destroy函数
    • 11. pthread_cond_wait函数
    • 12. pthread_cond_signal函数
  • 四、API的使用例子
    • 1. pthread_creat、pthread_exit、pthread_join、pthread_self函数
    • 2. pthread_mutex_init、pthread_mutex_destory、pthread_mutex_lock、pthread_mutex_unlock函数
    • 3. pthread_cond_init、pthread_cond_destory、pthread_cond_wait、pthread_cond_signal函数

一、概述

常规学习Linux系统编程的内容是复杂且繁多的,不推荐刚开始接触代码的朋友去学习,所以介绍Linux系统编程的目的主要是以应用开发为主。

1. 进程与线程的区别

  1. 进程——资源分配的最小单位,线程——程序执行的最小单位
  2. 在面向线程设计的系统中,进程本身不是基本运行单位,而是线程的容器。程序本身只是指令、数据及其组织形式的描述,进程才是程序 (那些指令和数据) 的真正运行实例。(程序是静态的,进程是动态的)
  3. 一个进程里边可以有多个线程。进程的所有信息对该进程的所有线程都是共享的,包括可执行的程序文本、程序的全局内存和堆内存、栈以及文件描述符。
  4. 进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。
  5. 总的来说:进程有独立的地址空间,线程没有单独的地址空间(同一进程内的线程共享进程的地址空间)。

2. 使用线程的理由

  1. 使用多线程的理由之一是和进程相比,它是一种非常"节俭"的多任务操作方式。我们知道,在Linux系统下,启动一个新的进程必须分配给它独立的地址空间,建立众多的数据表来维护它的代码段、堆栈段和数据段,这是一种"昂贵"的多任务工作方式。而运行于一个进程中的多个线程,它们彼此之间使用相同的地址空间,共享大部分数据,启动一个线程所花费的空间远远小于启动一个进程所花费的空间,而且,线程间彼此切换所需的时间也远远小于进程间切换所需要的时间。据统计,总的说来,一个进程的开销大约是一个线程开销的30倍左右,当然,在具体的系统上,这个数据可能会有较大的区别。
  2. 使用多线程的理由之二是线程间方便的通信机制。对不同进程来说,它们具有独立的数据空间,要进行数据的传递只能通过通信的方式进行,这种方式不仅费时,而且很不方便。线程则不然,由于同一进程下的线程之间共享数据空间,所以一个线程的数据可以直接为其它线程所用,这不仅快捷,而且方便。当然,数据的共享也带来其他一些问题,有的变量不能同时被两个线程所修改,有的子程序中声明为static的数据更有可能给多线程程序带来灾难性的打击,这些正是编写多线程程序时最需要注意的地方。

3. 互斥量

  1. 互斥量(mutex)从本质上来说是一把锁,在访问共享资源前对互斥量进行加锁,在访问完成后释放互斥量上的锁。对互斥量进行加锁后,任何其他试图再次对互斥量加锁的线程将会被阻塞直到当前线程释放该互斥锁。如果释放互斥锁时有多个线程阻塞,所有在该互斥锁上的阻塞线程都会变成可运行状态,第一个变为可运行状态的线程可以对互斥量加锁,其他线程将会看到互斥锁依然被锁住,只能回去等待它重新变为可用。在这种方式下,每次只有一个线程可以向前运行。
  2. 在设计时需要规定所有的线程必须遵守相同的数据访问规则。只有这样,互斥机制才能正常工作。操作系统并不会做数据访问的串行化。如果允许其中的某个线程在没有得到锁的情况下也可以访问共享资源,那么即使其它的线程在使用共享资源前都获取了锁,也还是会出现数据不一致的问题。
  3. 互斥变量用pthread_mutex_t数据类型表示。在使用互斥变量前必须对它进行初始化,可以把它置为常量PTHREAD_MUTEX_INITIALIZER(只对静态分配的互斥量),也可以通过调用pthread_mutex_init函数进行初始化。如果动态地分配互斥量(例如通过调用malloc函数),那么在释放内存前需要调用pthread_mutex_destroy。

4. 条件变量

  1. 条件变量是线程另一可用的同步机制。条件变量给多个线程提供了一个会合的场所。条件变量与互斥量一起使用时,允许线程以无竞争的方式等待特定的条件发生。
  2. 条件本身是由互斥量保护的。线程在改变条件状态前必须首先锁住互斥量,其他线程在获得互斥量之前不会察觉到这种改变,因为必须锁定互斥量以后才能计算条件。
  3. 条件变量使用之前必须首先初始化,pthread_cond_t数据类型代表的条件变量可以用两种方式进行初始化,可以把常量PTHREAD_COND_INITIALIZER赋给静态分配的条件变量,但是如果条件变量是动态分配的,可以使用pthread_cond_destroy函数对条件变量进行去除初始化(deinitialize)。

二、线程API

在Linux系统中,操作系统提供了一系列的API,详细看下图

1. 线程
创建		pthread_creat()
退出		pthread_exit()
等待		pthread_join()
获取ID		pthread_self()
2. 互斥锁
创建		pthread_mutex_init()
销毁		pthread_mutex_destroy()
加锁		pthread_mutex_lock()
解锁		pthread_mutex_unlock()
3. 条件
创建		pthread_cond_init()
销毁		pthread_cond_destroy()
触发		pthread_cond_signal()
广播		pthread_cond_broadcast()
等待		pthread_cond_wait() / pthread_cond_timewait()

三、API介绍

1. pthread_creat函数

#include <pthread.h>int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);1. 函数功能:创建线程
2. 形参说明:
tidp:线程ID
attr:线程属性。暂可以把它设置为NULL,以创建默认属性的线程。
start_rtn:新创建线程的运行函数
arg:函数运行传递的参数
3. 返回值:成功返回0,失败返回错误编号

2. pthread_exit函数

#include <pthread.h>int pthread_exit(void *rval_ptr);1. 函数功能:线程退出
2. 形参说明:
rival_ptr:退出时返回的数据

3. pthread_join函数

#include <pthread.h>int pthread_join(pthread_t thread, void **rval_ptr);1. 函数功能:调用这个函数的线程将一直阻塞,直到指定的线程调用pthread_exit、从启动例程中返回或者被取消。
2. 形参说明:
thread:线程ID
rival_ptr:线程退出时返回的数据
3. 返回值:成功返回0,失败返回错误编号

4. pthread_self函数

#include <pthread.h>pthread_t pthread_self(void);1. 函数功能:获取线程ID
2. 返回值:调用线程的ID

5. pthread_mutex_inti函数

#include <pthread.h>int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);1. 函数功能:创建互斥锁
2. 形参说明:
mutex:锁ID
attr:锁的属性。默认的属性初始化互斥量,只需把attr设置为NULL3. 返回值:成功返回0,失败返回错误编号

6. pthread_mutex_destroy函数

#include <pthread.h>int pthread_mutex_destroy(pthread_mutex_t *mutex);1. 函数功能:销毁互斥锁
2. 形参说明:
mutex:锁ID
3. 返回值:成功返回0,失败返回错误编号

7. pthread_mutex_lock函数

#include <pthread.h>int pthread_mutex_lock(pthread_mutex_t *mutex);1. 函数功能:加锁
2. 形参说明:
mutex:锁ID
3. 返回值:成功返回0,失败返回错误编号

8. pthread_mutex_unlock函数

#include <pthread.h>int pthread_mutex_unlock(pthread_mutex_t *mutex);1. 函数功能:解锁
2. 形参说明:
mutex:锁ID
3. 返回值:成功返回0,失败返回错误编号

9. pthread_cond_init函数

#include <pthread.h>int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);1. 函数功能:创建条件变量
2. 形参说明:
cond:条件ID
attr:条件属性。除非需要创建一个非默认属性的条件变量,否则该参数可以设置为NULL3. 返回值:成功返回0,失败返回错误编号

10. pthread_cond_destroy函数

#include <pthread.h>int pthread_cond_destroy(pthread_cond_t *cond);1. 函数功能:销毁条件变量
2. 形参说明:
cond:条件ID
3. 返回值:成功返回0,失败返回错误编号

11. pthread_cond_wait函数

#include <pthread.h>int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);1. 函数功能:等待条件为真
2. 形参说明:
cond:条件ID
mutex:锁ID
3. 返回值:成功返回0,失败返回错误编号

12. pthread_cond_signal函数

#include <pthread.h>int pthread_cond_signal(pthread_cond_t *cond);1. 函数功能:触发条件
2. 形参说明:
cond:条件ID
3. 返回值:成功返回0,失败返回错误编号

四、API的使用例子

1. pthread_creat、pthread_exit、pthread_join、pthread_self函数

  1 #include <stdio.h>2 #include <stdlib.h>3 #include <string.h>4 5 #include <pthread.h>6 7 // 1. int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*    start_rtn)(void *), void *restrict arg);8 // 2. pthread_t pthread_self(void);9 // 3. int pthread_join(pthread_t thread, void **rval_ptr);10 // 4. int pthread_exit(void *rval_ptr);11 12 void *func1(void *arg)13 {14     static int data = 10;15 16     printf("t1: %ld\n", pthread_self()); //打印线程ID17     printf("t1: arg = %d\n", *((int *)arg)); //打印传递的参数18 19     pthread_exit((void *)(&data)); //线程退出并返回数据20 }21 22 int main()23 {24     int ret = 0;25     int param = 100;26     int *pret = NULL;27 28     pthread_t t1; //线程ID29 30     ret = pthread_create(&t1, NULL, func1, (void *)&param); //创建线程31 32     if(ret == 0){33         printf("main: %ld, pthread create success\n", pthread_self());34     }35 36     pthread_join(t1, (void **)(&pret)); //等待线程退出37 38     printf("main: pret = %d\n", *pret); //打印线程退出时反馈的的数据39 40     return 0;41 }

2. pthread_mutex_init、pthread_mutex_destory、pthread_mutex_lock、pthread_mutex_unlock函数

  1 #include <stdio.h>2 #include <stdlib.h>3 #include <string.h>4 5 #include <pthread.h>6 7 // 1. int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restric    t attr);8 // 2. int pthread_mutex_destroy(pthread_mutex_t *mutex);9 // 3. int pthread_mutex_lock(pthread_mutex_t *mutex);10 // 4. int pthread_mutex_unlock(pthread_mutex_t *mutex);11 12 int g_data = 0;13 14 pthread_mutex_t mutex; //锁15 16 void *func1(void *arg)17 {18     printf("t1: %ld\n", pthread_self()); //打印线程ID19     printf("t1: arg = %d\n", *((int *)arg)); //打印传递过来的数据20 21     pthread_mutex_lock(&mutex); //加锁22 23     while(1){24         printf("t1: %d\n", g_data++);25 26         if(g_data == 3){27             printf("t1 quit===========================\n");28             pthread_mutex_unlock(&mutex); //当g_data = 3时解锁29             pthread_exit(NULL); //线程退出30         }31 32         sleep(1);33     }34 35 }36 37 void *func2(void *arg)38 {39     printf("t2: %ld\n", pthread_self());40     printf("t2: arg = %d\n", *((int *)arg));41 42     while(1){43         pthread_mutex_lock(&mutex); //加锁44 45         printf("t2: %d\n", g_data++);46 47         pthread_mutex_unlock(&mutex); //解锁48 49         sleep(1);50     }51 }52 53 int main()54 {55     int ret = 0;56     int param = 100;57 58     pthread_t t1;59     pthread_t t2;60 61     pthread_mutex_init(&mutex, NULL); //创建互斥锁62 63     ret = pthread_create(&t1, NULL, func1, (void *)&param); //创建线程164 65     if(ret == 0){66         //printf("main: t1:%ld, pthread create success\n", pthread_self());67     }68 69     ret = pthread_create(&t2, NULL, func2, (void *)&param); //创建线程270 71     if(ret == 0){72         //printf("main: t2:%ld, pthread create success\n", pthread_self());73     }74 75     pthread_join(t1, NULL); //等待线程1退出76     pthread_join(t2, NULL); //等待线程2退出77 78     pthread_mutex_destroy(&mutex); //销毁互斥锁79 80     return 0;81 }

3. pthread_cond_init、pthread_cond_destory、pthread_cond_wait、pthread_cond_signal函数

1. 动态初始化

  1 #include <stdio.h>2 #include <stdlib.h>3 #include <string.h>4 5 #include <pthread.h>6 7 // 1. int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*    start_rtn)(void *), void *restrict arg);8 // 2. pthread_t pthread_self(void);9 // 3. int pthread_join(pthread_t thread, void **rval_ptr);10 // 4. int pthread_exit(void *rval_ptr);11 // 5. int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mut    exattr_t *res    trict attr);12 // 6. int pthread_mutex_destroy(pthread_mutex_t *mutex);13 // 7. int pthread_mutex_lock(pthread_mutex_t *mutex);14 // 8. int pthread_mutex_unlock(pthread_mutex_t *mutex);15 // 9. int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict at    tr);16 // 10. int pthread_cond_destroy(pthread_cond_t *cond);17 // 11. int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);18 // 12. int pthread_cond_signal(pthread_cond_t *cond);19 20 int g_data = 0;21 22 pthread_cond_t cond; //条件变量23 pthread_mutex_t mutex; //锁24 25 void *func1(void *arg)26 {27     printf("t1: %ld\n", pthread_self()); //打印线程ID28     printf("t1: arg = %d\n", *((int *)arg)); //打印传递过来的数据29 30     while(1){31         pthread_cond_wait(&cond, &mutex); //等待条件为真32 33         printf("t1 run=========================\n");34         printf("t1: %d\n", g_data);35         g_data = 0;36 37         sleep(1);38     }39 }40 41 void *func2(void *arg)42 {43     printf("t2: %ld\n", pthread_self());44     printf("t2: arg = %d\n", *((int *)arg));45 46     while(1){47         pthread_mutex_lock(&mutex); //加锁48 49         printf("t2: %d\n", g_data++);50         if(g_data == 3){51             pthread_cond_signal(&cond); //当g_data = 3时,触发条件,唤醒等待该条件的线程52         }53 54         pthread_mutex_unlock(&mutex); //解锁55 56         sleep(1);57     }58 }59 60 int main()61 {62     int ret = 0;63     int param = 100;64 65     pthread_t t1;66     pthread_t t2;67 68     pthread_cond_init(&cond, NULL); //创建条件变量69     pthread_mutex_init(&mutex, NULL); //创建互斥锁70 71     ret = pthread_create(&t1, NULL, func1, (void *)&param); //创建线程172 73     if(ret == 0){74         //printf("main: t1:%ld, pthread create success\n", pthread_self());75     }76 77     ret = pthread_create(&t2, NULL, func2, (void *)&param); //创建线程278 79     if(ret == 0){80         //printf("main: t2:%ld, pthread create success\n", pthread_self());81     }82 83     pthread_join(t1, NULL); //等待线程1退出84     pthread_join(t2, NULL); //等待线程2退出85 86     pthread_cond_destroy(&cond); //销毁条件变量87     pthread_mutex_destroy(&mutex); //销毁互斥锁88 89     return 0;90 }

2. 静态初始化

  1 #include <stdio.h>2 #include <stdlib.h>3 #include <string.h>4 5 #include <pthread.h>6 7 // 1. int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*    start_rtn)(void *), void *restrict arg);8 // 2. pthread_t pthread_self(void);9 // 3. int pthread_join(pthread_t thread, void **rval_ptr);10 // 4. int pthread_exit(void *rval_ptr);11 // 5. int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mut    exattr_t *res    trict attr);12 // 6. int pthread_mutex_destroy(pthread_mutex_t *mutex);13 // 7. int pthread_mutex_lock(pthread_mutex_t *mutex);14 // 8. int pthread_mutex_unlock(pthread_mutex_t *mutex);15 // 9. int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict at    tr);16 // 10. int pthread_cond_destroy(pthread_cond_t *cond);17 // 11. int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);18 // 12. int pthread_cond_signal(pthread_cond_t *cond);19 20 int g_data = 0;21 22 pthread_cond_t cond = PTHREAD_COND_INITIALIZER; //初始化条件变量23 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; //初始化互斥锁24 25 void *func1(void *arg)26 {27     printf("t1: %ld\n", pthread_self()); //打印线程ID28     printf("t1: arg = %d\n", *((int *)arg)); //打印传递过来的值29 30     while(1){31         pthread_cond_wait(&cond, &mutex); //等待条件为真32 33         printf("t1 run=========================\n");34         printf("t1: %d\n", g_data);35         g_data = 0;36 37         sleep(1);38     }39 }40 41 void *func2(void *arg)42 {43     printf("t2: %ld\n", pthread_self()); //打印线程ID44     printf("t2: arg = %d\n", *((int *)arg)); //打印传递过来的值45 46     while(1){47         pthread_mutex_lock(&mutex); //加锁48 49         printf("t2: %d\n", g_data++);50         if(g_data == 3){51             pthread_cond_signal(&cond); //当g_data = 3时,触发条件,唤醒等待该条件的线程52         }53 54         pthread_mutex_unlock(&mutex); //解锁55 56         sleep(1);57     }58 }59 60 int main()61 {62     int ret = 0;63     int param = 100;64 65     pthread_t t1;66     pthread_t t2;67 68     //pthread_cond_init(&cond, NULL);69     //pthread_mutex_init(&mutex, NULL);70 71     ret = pthread_create(&t1, NULL, func1, (void *)&param); //创建线程172 73     if(ret == 0){74         //printf("main: t1:%ld, pthread create success\n", pthread_self());75     }76 77     ret = pthread_create(&t2, NULL, func2, (void *)&param); //创建线程278 79     if(ret == 0){80         //printf("main: t2:%ld, pthread create success\n", pthread_self());81     }82 83     pthread_join(t1, NULL); //等待线程1退出84     pthread_join(t2, NULL); //等待线程2退出85 86     pthread_cond_destroy(&cond); //销毁条件变量87     pthread_mutex_destroy(&mutex); //销毁互斥锁88 89     return 0;90 }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/87572.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python爬虫从端到端抓取网页

网页抓取和 REST API 简介 网页抓取是使用计算机程序以自动方式从网站提取和解析数据的过程。这是创建用于研究和学习的数据集的有用技术。虽然网页抓取通常涉及解析和处理 HTML 文档&#xff0c;但某些平台还提供 REST API 来以机器可读格式&#xff08;如 JSON&#xff09;检…

【C++】C++ 类中的 this 指针用法 ③ ( 全局函数 与 成员函数 相互转化 | 有参构造函数设置默认参数值 | 返回匿名对象与返回引用 )

文章目录 一、全局函数 与 成员函数 相互转化1、成员函数转为全局函数 - 多了一个参数2、全局函数转为成员函数 - 通过 this 指针隐藏操作数 二、有参构造函数设置默认参数值三、返回匿名对象与返回引用四、完整代码示例 一、全局函数 与 成员函数 相互转化 1、成员函数转为全局…

一、vue2的基础语法巩固

一、定义&#xff1a;是一个渐进式的JavaScript框架 二、特点&#xff1a; 减少了大量的DOM操作编写 &#xff0c;可以更专注于逻辑操作分离数据和界面的呈现&#xff0c;降低了代码耦合度(前端端分离)支持组件化开发&#xff0c;更利于中大型项目的代码组织 vue2核心功能&a…

【Linux】生产消费模型 + 线程池

文章目录 &#x1f4d6; 前言1. 生产消费模型2. 阻塞队列2.1 成员变量&#xff1a;2.2 入队(push)和出队(pop)&#xff1a;2.3 封装与测试运行&#xff1a;2.3 - 1 对代码进一步封装2.3 - 2 分配运算任务2.3 - 3 测试与运行 3. 循环阻塞队列3.1 POSIX信号量&#xff1a;3.1 - 1…

Python 解释器配置需要注意什么?

Python是一种广泛使用的编程语言&#xff0c;被用于开发各种类型的软件应用程序。在Python中&#xff0c;解释器是负责将Python代码转换为机器语言的程序。 因此&#xff0c;正确配置Python解释器是非常重要的&#xff0c;这有助于提高代码的性能、可读性和可维护性。下面将探…

vue3中使用editor.js

第一步安装依赖 npm i editorjs/editorjs --save 第二步创建editor.vue插件 <template><div><div id"editorjs" :style"width: props.width px;height: props.height px;"></div></div> </template> <scrip…

WKB近似

WKB方法用于研究一种特定类型的微分方程的全局性质 很有用这种特定的微分方程形如&#xff1a; 经过一些不是特别复杂的推导&#xff0c;我们可以得到他的WKB近似解。 该近似解的选择取决于函数和参数的性质同时&#xff0c;我们默认函数的定义域为当恒大于零,时&#xff1a; 当…

44.java教程

目录 一、Java 教程。 &#xff08;1&#xff09;我的第一个 JAVA 程序。 &#xff08;2&#xff09;Java 简介。 &#xff08;2.1&#xff09;java简介。 &#xff08;2.2&#xff09;主要特性。 &#xff08;2.3&#xff09;发展历史。 &#xff08;2.4&#xff09;J…

iOS应用程序的签名、重签名和安装测试

目录 前言 打开要处理的IPA文件 设置签名使用的证书和描述文件 开始ios ipa重签名 前言 ipa编译出来后&#xff0c;或者ipa进行修改后&#xff0c;需要进行重新签名才能安装到测试手机&#xff0c;或者提交app store供apple 商店审核上架。ipaguard有签名和重签名功能&…

吴恩达ChatGPT《Finetuning Large Language Models》笔记

课程地址&#xff1a;https://learn.deeplearning.ai/finetuning-large-language-models/lesson/1/introduction Introduction 动机&#xff1a;虽然编写提示词&#xff08;Prompt&#xff09;可以让LLM按照指示执行任务&#xff0c;比如提取文本中的关键词&#xff0c;或者对…

React中setState的原理及深层理解

1.为什么使用setState React并没有实现类似于Vue2中的Object.defineProperty或者Vue3中的Proxy的方式来监听数据的变化 我们必须通过setState来告知React数据已经发生了变化 setState方法是从Component中继承过来的。 2.setState异步更新 setState设计为异步&#xff0c;可…

PHY6230低成本遥控灯控芯片国产蓝牙BLE5.2 2.4G SoC

高性价比的低功耗高性能蓝牙5.2系统级芯片&#xff0c;适用多种PC/手机外设连接场景。 高性能多模射频收发机&#xff1a; 通过硬件模块的充分复用实现高性能多模数字收发机。发射机&#xff0c;最大发射功率10dBm&#xff1b;BLE 1Mbps速率接收机灵敏度达到-96dBm&#xff1…

解决Vue设置图片的动态src不生效的问题

一、问题描述 在vue项目中&#xff0c;想要动态设置img的src时&#xff0c;此时发现图片会加载失败。在Vue代码中是这样写的&#xff1a; 在Vue的data中是这样写的&#xff1a; 我的图片在根目录下的static里面&#xff1a; 但是在页面上这个图片却无法加载出来。 二、解决方案…

五、核支持向量机算法(NuSVC,Nu-Support Vector Classification)(有监督学习)

和支持向量分类(Nu-Support Vector Classification)&#xff0c;与 SVC 类似&#xff0c;但使用一个参数来控制支持向量的数量&#xff0c;其实现基于libsvm 一、算法思路 本质都是SVM中的一种优化&#xff0c;原理都类似&#xff0c;详细算法思路可以参考博文&#xff1a;三…

10分钟让你拿下Linux常用命令,网安运维测试人员必掌握!

文章目录 一、目录操作 1、批量操作 二、文件操作三、文件内容操作&#xff08;查看日志&#xff0c;更改配置文件&#xff09; 1、grep(检索文件内容)2、awk(数据统计)3、sed(替换文件内容)4、管道操作符|5、cut(数据裁剪) 四、系统日志位置五、创建与删除软连接六、压缩和解压…

虹科案例 | ELPRO帮助客户实现符合GDP标准的温度监测和高效的温度数据管理

文章来源&#xff1a;虹科环境监测技术 点击阅读原文&#xff1a;https://mp.weixin.qq.com/s/wwIPx_GK3ywqWr5BABC4KQ 在本案例研究中&#xff0c;虹科ELPRO帮助客户 ● 实施了温度监测解决方案&#xff0c;以一致的数据结构获取各国和各种运输方式的数据; ● 通过将温度数据上…

https跳过SSL认证时是不是就是不加密的,相当于http?

https跳过SSL认证时是不是就是不加密的,相当于http?&#xff0c;其实不是&#xff0c;HTTPS跳过SSL认证并不相当于HTTP&#xff0c;也不意味着没有加密。请注意以下几点&#xff1a; HTTPS&#xff08;Hypertext Transfer Protocol Secure&#xff09;本质上是在HTTP的基础上…

【postgresql】ERROR: column “xxxx.id“ must appear in the GROUP BY

org.postgresql.util.PSQLException: ERROR: column "xxx.id" must appear in the GROUP BY clause or be used in an aggregate function 错误&#xff1a;列“XXXX.id”必须出现在GROUP BY子句中或在聚合函数中使用 在mysql中是正常使用的&#xff0c;在postgre…

数字IC笔试千题解--单选题篇(二)

前言 出笔试题汇总&#xff0c;是为了总结秋招可能遇到的问题&#xff0c;做题不是目的&#xff0c;在做题的过程中发现自己的漏洞&#xff0c;巩固基础才是目的。 所有题目结果和解释由笔者给出&#xff0c;答案主观性较强&#xff0c;若有错误欢迎评论区指出&#xff0c;资料…

概率论的相关知识

理解随机变量 X X X和 x x x的区别&#xff0c; F X ( x ) F_X(x) FX​(x)、 f X ( x ) f_X(x) fX​(x) X X X代表的是随机变量&#xff0c; x x x是样本值&#xff0c;是 X X X的具体取值&#xff0c;分布函数 F X ( x ) F_X(x) FX​(x)和概率密度 f X ( x ) f_X(x) fX​(x)中…