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

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 }

相关文章:

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

学习参考博文&#xff1a; Linux多线程编程初探 Linux系统编程学习相关博文 Linux系统编程——文件编程的学习Linux系统编程——进程的学习Linux系统编程——进程间通信的学习Linux系统编程——网络编程的学习 Linux系统编程——线程的学习 一、概述1. 进程与线程的区别2. 使…...

zemaxMIF曲线图

调制传递函数&#xff08; Modulation Transfer Function&#xff0c;MTF &#xff09;是用来形容光学系统成像质量的重要指标。 通过对光学系统像空间进行傅里叶变换&#xff0c;可以得到一张分析图表&#xff0c;来描述像面上对比度和空间频率之间的对应关系。 对比度&…...

【苹果】SpringBoot监听Iphone15邮件提醒,Selenium+Python自动化抢购脚本

前言 &#x1f34a;缘由 Iphone15来了&#xff0c;两年之约你还记得吗&#xff1f; 两年前&#xff0c;与特别的人有一个特别的约定。虽物是人非&#xff0c;但思念仍在。 遂整合之前iphone13及iphone14的相关抢购代码&#xff0c;完成一个SpringBoot监听Iphone15有货邮件提…...

什么是WhatsApp群发,WhatsApp协议,WhatsApp云控

那么WhatsApp群控云控可以做什么呢&#xff1f; 1、获客 自动化引流&#xff0c;强大的可控性&#xff0c;产品快速拓客 2、导流 一键式傻瓜化自动加好友&#xff0c;群发&#xff0c;朋友圈营销 3、群控 一键式拉群好友&#xff0c;建群&#xff0c;进群 …...

RealVNC viewer 窗口指定默认显示

RealVNC Viewer关于显示器(monitor)的参数有两个&#xff0c;一个是monitor&#xff0c;一个是useallmonitor。 monitor就是指定viewer窗体在哪个显示器上显示的&#xff0c;windows下的默认值是空白&#xff0c;改为\\.\DISPLAY2 就可以在打开远程窗口的时候默认在副屏上显…...

图论20(Leetcode1254.统计封闭岛屿的数目)

代码&#xff1a; class Solution {static int[][] dirs {{1,0},{-1,0},{0,1},{0,-1}};public int closedIsland(int[][] grid) {int num 0; for(int i0;i<grid.length;i){for(int j0;j<grid[0].length;j){if(grid[i][j]0){int[] start {i,j};if(getIsland(start,gri…...

Docker 的基本概念和优势,以及在应用程序开发中的实际应用

Docker是一种开源的容器化平台&#xff0c;它可以将应用程序打包成容器&#xff0c;并且可以在不同的环境中运行。Docker的基本概念包括&#xff1a; 镜像&#xff08;Image&#xff09;&#xff1a;Docker镜像是一个可执行的包&#xff0c;它包含了运行应用程序所需的所有文件…...

数据仓库整理

数仓 olap vs oltp OLTP主要用于支持日常的业务操作&#xff0c;如银行交易、电子商务等&#xff0c;强调数据的准确性、实时性和并发性。OLAP主要用于支持复杂的数据分析&#xff0c;如数据仓库、决策支持等&#xff0c;强调数据的维度、聚合和可视化。 将OLTP数据库的数据…...

《C++API设计》读书笔记(3):模式

本章内容 本章涵盖了一些与CAPI设计相关的设计模式和惯用法。 “设计模式(Design Pattern)”表示软件设计问题的一些通用解决方案。该术语来源于《设计模式&#xff1a;可复用面向对象软件的基础》&#xff08;Design Patterns: Elements of Reusable Object-Oriented Softwar…...

小程序搜索词优化:小陈运营的秘密武器

大家好&#xff0c;我是小陈&#xff0c;今天要和大家分享一下小程序搜索词优化的经验和技巧。在数字化时代&#xff0c;小程序已经成为许多企业的重要工具&#xff0c;但要让小程序在竞争激烈的市场中脱颖而出&#xff0c;搜索词优化是不可或缺的一环。在本文中&#xff0c;我…...

SpringSecurity 入门

文章目录 Spring Security概念快速入门案例环境准备Spring配置文件SpringMVC配置文件log4j配置文件web.xmlTomcat插件 整合SpringSecurity 认证操作自定义登录页面关闭CSRF拦截数据库认证加密认证状态记住我授权注解使用标签使用 Spring Security概念 Spring Security是Spring…...

【每日一题Day335】LC1993树上的操作 | dfs

树上的操作【LC1993】 给你一棵 n 个节点的树&#xff0c;编号从 0 到 n - 1 &#xff0c;以父节点数组 parent 的形式给出&#xff0c;其中 parent[i] 是第 i 个节点的父节点。树的根节点为 0 号节点&#xff0c;所以 parent[0] -1 &#xff0c;因为它没有父节点。你想要设计…...

FPGA:卷积编码及维特比译码仿真

FPGA&#xff1a;卷积编码及维特比译码仿真 本篇记录一下在FPGA中完成卷积编码和维特比译码的过程&#xff0c;通过代码解释编码的过程和译码的过程&#xff0c;便于理解&#xff0c;同时也方便移植到其他工程中。 1. 准备工作 卷积编译码IP核—convolutionIP核和viterbiIP核…...

MySQL学习笔记4

客户端工具的使用&#xff1a; MySQL&#xff1a; mysql命令行工具&#xff0c;一般用来连接访问mysql的数据。 案例&#xff1a;使用mysql客户端工具连接服务器端&#xff08;用户名&#xff1a;root&#xff1b;密码&#xff1a;123456&#xff09;. [rootmysql-server ~]#…...

JavaFX:窗体显示状态,模态非模态

程序窗体显示一般有3中模式。非模态和模态&#xff0c;其中模态又分为程序模态和窗体模态。 非模态可以理解为窗体之间没有任何限制&#xff0c;可以用鼠标、键盘等工具在窗体间切换。 程序模态是窗体打开后&#xff0c;该程序的所有窗体都被冻结&#xff0c;无法切换&#x…...

C++17中std::filesystem::path的使用

C17引入了std::filesystem库(文件系统库, filesystem library)。这里整理下std::filesystem::path的使用。 std::filesystem::path&#xff0c;文件系统路径&#xff0c;提供了对文件系统及其组件(例如路径、常规文件和目录)执行操作的工具。此path类主要用法包括&#x…...

命令模式简介

概念&#xff1a; 命令模式是一种行为设计模式&#xff0c;它将请求封装成一个对象&#xff0c;从而允许您将不同的请求参数化、队列化&#xff0c;并且能够在不同的时间点执行。通过引入命令对象&#xff08;Command&#xff09;来解耦发送者&#xff08;Invoker&#xff09;…...

Boost序列化指针

Boost.Serialization 还能序列化指针和引用。 由于指针存储对象的地址&#xff0c;序列化对象的地址没有什么意义&#xff0c;而是在序列化指针和引用时&#xff0c;对象的引用被自动地序列化。 代码 #include <boost/archive/text_oarchive.hpp> #include <boost/…...

NIO简单介绍

一、什么是NIO 1、Java NIO全称java non-blocking IO&#xff0c; 是指JDK提供的新API。从JDK1.4开始&#xff0c;Java提供了一系列改进的输入/输出的新特性&#xff0c;被统称为NIO(即New IO)&#xff0c;是同步非阻塞的 2、NIO有三大核心部分: Channel(通道)&#xff0c; Buf…...

linux进程杀不死

项目场景&#xff1a; 虚拟机 问题描述 linux进程杀不死 无反应 原因分析&#xff1a; 进程僵死zombie 解决方案&#xff1a; 进proc或者find命令找到进程所在地址 cat status查看进程杀死子进程...

5分钟带你搞懂RPA到底是什么?RPA能做什么?

一、RPA的定义 RPA&#xff0c;全称Robotic Process Automation&#xff0c;即机器人流程自动化&#xff0c;是一种软件解决方案&#xff0c;能够模拟人类在计算机上执行的操作&#xff0c;以实现重复性、繁琐任务的自动化。它与传统的计算机自动化有所不同&#xff0c;因为它…...

毫米波雷达 TI IWR1443 在 ROS 中进行 octomap 建图

个人实验记录 /mmwave_ti_ros/ros_driver/src/ti_mmwave_rospkg/launch/1443_multi_3d_0.launch <launch><!-- Input arguments --><arg name"device" value"1443" doc"TI mmWave sensor device type [1443, 1642]"/><arg…...

113双周赛

题目列表 2855. 使数组成为递增数组的最少右移次数 2856. 删除数对后的最小数组长度 2857. 统计距离为 k 的点对 2858. 可以到达每一个节点的最少边反转次数 一、使数组成为递增数组的最少右移次数 这题可以直接暴力求解&#xff0c;枚举出每种右移后的数组&#xff0c;将…...

React 全栈体系(九)

第五章 React 路由 一、相关理解 1. SPA 的理解 单页 Web 应用&#xff08;single page web application&#xff0c;SPA&#xff09;。整个应用只有一个完整的页面。点击页面中的链接不会刷新页面&#xff0c;只会做页面的局部更新。数据都需要通过 ajax 请求获取, 并在前端…...

阈值化分割,对灰度级图像进行二值化处理(数字图像处理大题复习 P8)

文章目录 画出表格求出灰度直方图 & 山谷画出结果图 画出表格 有几个0就写几&#xff0c;有几个1就写几&#xff0c;如图 求出灰度直方图 & 山谷 跟前面求灰度直方图的方法一样&#xff0c;找出谷底&#xff0c;发现结果为 4 画出结果图 最终的结果就是&#xf…...

vue3中withDefaults是什么

问: const props withDefaults(defineProps<{// 数据列表lotteryList: { pic: string; name?: string }[];// 中奖idwinId: number;// 抽奖初始转动速度initSpeed: number;// 抽奖最快转动速度fastSpeed: number;// 抽奖最慢转动速度slowSpeed: number;// 基本圈数baseCi…...

Android进阶之路 - 盈利、亏损金额格式化

在金融类型的app中&#xff0c;关于金额、数字都相对敏感和常见一些&#xff0c;在此仅记录我在金融行业期间学到的皮毛&#xff0c;如后续遇到新的场景也会加入该篇 该篇大多采用 Kotlin 扩展函数的方式进行记录&#xff0c;尽可能熟悉 Kotlin 基础知识 兄弟 Blog StringUti…...

工业蒸汽量预测(速通一)

工业蒸汽量预测&#xff08;一&#xff09; 赛题理解1、评估指标2、赛题模型3、解题思路 理论知识1、变量识别2、变量分析3、缺失值处理4、异常值处理5、变量转换6、新变量生成 数据探索1、导包2、读取数据3、查看数据4、可视化数据分布4.1箱型图4.2获取异常数据并画图4.3直方图…...

机器学习的主要内容

分类任务 回归任务 有一些算法只能解决回归问题有一些算法只能解决分类问题有一些算法的思路既能解决回归问题&#xff0c;又能解决分类问题 一些情况下&#xff0c; 回归任务可以转化为分类任务&#xff0c; 比如我们预测学生的成绩&#xff0c;然后根据学生的成绩划分为A类、…...

华为OD机试真题-分积木-2023年OD统一考试(B卷)

题目描述: Solo和koko是两兄弟,妈妈给了他们一大堆积木,每块积木上都有自己的重量。现在他们想要将这些积木分成两堆。哥哥Solo负责分配,弟弟koko要求两个人获得的积木总重量“相等”(根据Koko的逻辑),个数可以不同,不然就会哭,但koko只会先将两个数转成二进制再进行加…...