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

5守护进程与线程

进程组

多个进程的集合,第一个进程就是组长,组长进程的PID等于进程组ID。

进程组生存期:进程组创建到最后一个进程离开(终止或转移到另一个进程组)。与组长进程是否终止无关。

一个进程可以为自己或子进程设置进程组 ID

相关函数

pid_t getpgrp(void);
得到当前进程所在的进程组的组 IDpid_t getpgid(pid_t pid);
获取指定的进程所在的进程组的组 ID,参数 pid 就是指定的进程,0当前进程int setpgid(pid_t pid, pid_t pgid);
将某个进程移动到其他进程组中或者创建新的进程组参数:pid: 某个进程的进程 IDpgid: 某个进程组的组 ID如果 pgid 对应的进程组存在,pid 对应的进程会移动到这个组中,pid != pgid如果 pgid 对应的进程组不存在,会创建一个新的进程组,因此要求 pid == pgid, 当前进程就是组长了返回值:函数调用成功返回 0,失败返回 - 1

setpgid设置子进程组id

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>int main(int argc, char *argv[])
{pid_t pid;pid = fork();if(pid == 0 ){printf("我是子进程:%d,我的进程组id是:%d\n",getpid(),getpgrp());setpgid(pid,pid);  //设置子进程的组id为自己的pid,默认是父进程的pidprintf("我是子进程:%d,我的进程组id是:%d\n",getpid(),getpgrp());}else if(pid > 0){sleep(1);printf("我是父进程:%d,我的进程组id是:%d\n",getpid(),getpgrp());wait(NULL);}return 0;
}

会话

多个进程组的集合

获取进程所属的会话 ID
pid_t getsid(pid_t pid); 
成功:返回调用进程的会话 ID;失败:-1,设置 errno
pid 为 0 表示察看当前进程 session ID创建一个会话,并以自己的 ID 设置进程组 ID,同时也是新会话的 ID。
pid_t setsid(void); 
成功:返回调用进程的会话 ID;失败:-1,设置 errno
调用了 setsid 函数的进程,既是新的会长,也是新的组长。

注意事项:

调用进程不能是进程组组长,该进程变成新会话首进程(session header),建立新会话时,先调用 fork, 父进程终止,子进程调用 setsid(),
#include <stdio.h>
#include <unistd.h>int main(int argc, char *argv[])
{pid_t pid;pid = fork();if(pid == 0){printf("我是子进程id:%d,进程组id:%d,会话id:%d\n",getpid(),getpgid(0),getsid(0));printf("change--------------\n");sleep(2);setsid();printf("我是子进程id:%d,进程组id:%d,会话id:%d\n",getpid(),getpgid(0),getsid(0));}else{sleep(3);printf("我是父进程id:%d,进程组id:%d,会话id:%d\n",getpid(),getpgid(0),getsid(0));}return 0;
}

编译执行结果

我是子进程id:44801,进程组id:44800,会话id:39560  #默认子进程的进程组id是父进程的pid,会话id是当前bash的pid
change--------------
我是子进程id:44801,进程组id:44801,会话id:44801  #setsid后,进程组id,会话id都变成子进程的pid
我是父进程id:44800,进程组id:44800,会话id:39560

守护进程

daemon进程。通常运行与操作系统后台,脱离控制终端。一般不与用户直接交互。周期性的等待某个事件发生或周期性执行某一动作。

不受用户登录注销影响。通常采用以d结尾的命名方式。

Linux 后台的一些系统服务进程,没有控制终端,不能直接和用户交互。不受用户登录、注销的影响,一直在运行着,他们都是守护进程。

创建守护进程

创建守护进程,最关键的一步是调用 setsid 函数创建一个新的 Session,并成为 Session Leader。

1. fork子进程,让父进程终止。2. 子进程调用 setsid() 创建新会话3. 通常根据需要,改变工作目录位置 chdir(), 防止目录被卸载。4. 通常根据需要,重设umask文件权限掩码,影响新文件的创建权限。  022 -- 755	0345 --- 432   r---wx-w-   4225. 通常根据需要,关闭/重定向 文件描述符6. 守护进程 业务逻辑。while()
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/time.h>
#include <string.h>void func(int signo)
{int fd1;fd1 = open("./lc.txt",O_RDWR|O_CREAT|O_APPEND,0664);  //fd1 = 3 符合默认的习惯if(fd1 == -1 ){perror("open lc.txt error");exit(1);}char *str="heppy new year\n";write(fd1,str,strlen(str));close(fd1);
}int main(int argc, char *argv[])
{pid_t pid;int fd,fd1;pid = fork();if(pid > 0){exit(1);}pid_t pid1 = setsid();if(pid1 == -1 ){perror("open lc.txt error");exit(1);}chdir("/home/lc");  //切换到一个不可能被删除卸载的目录umask(0022); //默认umask是0002,默认创建普通文件默认属性是664close(STDIN_FILENO);  //close 0fd = open("/dev/null",O_RDWR);    //fd = 0if(fd == -1 ){perror("open /dev/null error");exit(1);}dup2(fd, STDOUT_FILENO); // 重定向 stdout和stderr  1 -->0dup2(fd, STDERR_FILENO); // 2--> 0,//捕捉信号struct sigaction act;act.sa_handler = func;act.sa_flags = 0;sigemptyset(&act.sa_mask);sigaction(SIGALRM,&act,NULL);
//      signal(SIGALRM,func);//设置定时器struct itimerval it;it.it_interval.tv_sec = 10;it.it_interval.tv_usec = 0;it.it_value.tv_sec = 10;it.it_value.tv_usec = 0;setitimer(ITIMER_REAL,&it,NULL);while (1);              // 模拟 守护进程业务.return 0;
}

线程

LWP,(light weight process)轻量级的进程,在linux环境下线程的本质仍然是进程,

进程:有独立的 进程地址空间。有独立的pcb。	分配资源的最小单位。可看成是只有一个线程的进程线程:有独立的pcb。没有独立的进程地址空间。	最小单位的执行。
[root@lc133 ~]# ps -aux | grep mysql | grep -v grep
mysql      1620  0.4 20.2 1793004 405880 ?      Ssl  08:20   1:36 /usr/sbin/mysqld
Ssl:休眠,拥有子进程,多线程
[root@lc133 ~]# ps -Lf 1620
UID         PID   PPID    LWP  C NLWP STIME TTY      STAT   TIME CMD
mysql      1620      1   1620  0   38 08:20 ?        Ssl    0:01 /usr/sbin/mysqld
mysql      1620      1   1669  0   38 08:20 ?        Ssl    0:00 /usr/sbin/mysqld
mysql      1620      1   1670  0   38 08:20 ?        Ssl    0:00 /usr/sbin/mysqld
mysql      1620      1   1671  0   38 08:20 ?        Ssl    0:00 /usr/sbin/mysqld
mysql      1620      1   1672  0   38 08:20 ?        Ssl    0:00 /usr/sbin/mysqld
mysql      1620      1   1674  0   38 08:20 ?        Ssl    0:00 /usr/sbin/mysqld
mysql      1620      1   1675  0   38 08:20 ?        Ssl    0:00 /usr/sbin/mysqld
mysql      1620      1   1676  0   38 08:20 ?        Ssl    0:00 /usr/sbin/mysqld
mysql      1620      1   1677  0   38 08:20 ?        Ssl    0:00 /usr/sbin/mysqld
mysql      1620      1   1678  0   38 08:20 ?        Ssl    0:00 /usr/sbin/mysqld
mysql      1620      1   1679  0   38 08:20 ?        Ssl    0:00 /usr/sbin/mysqld
mysql      1620      1   1680  0   38 08:20 ?        Ssl    0:00 /usr/sbin/mysqld
mysql      1620      1   1724  0   38 08:20 ?        Ssl    0:00 /usr/sbin/mysqld
mysql      1620      1   1725  0   38 08:20 ?        Ssl    0:04 /usr/sbin/mysqld
mysql      1620      1   1726  0   38 08:20 ?        Ssl    0:04 /usr/sbin/mysqld
mysql      1620      1   1727  0   38 08:20 ?        Ssl    0:04 /usr/sbin/mysqld
mysql      1620      1   1728  0   38 08:20 ?        Ssl    0:04 /usr/sbin/mysqld
mysql      1620      1   1729  0   38 08:20 ?        Ssl    0:55 /usr/sbin/mysqld
mysql      1620      1   1786  0   38 08:20 ?        Ssl    0:00 /usr/sbin/mysqld
mysql      1620      1   1787  0   38 08:20 ?        Ssl    0:00 /usr/sbin/mysqld
mysql      1620      1   1788  0   38 08:20 ?        Ssl    0:00 /usr/sbin/mysqld
mysql      1620      1   1793  0   38 08:20 ?        Ssl    0:00 /usr/sbin/mysqld
mysql      1620      1   1794  0   38 08:20 ?        Ssl    0:00 /usr/sbin/mysqld
mysql      1620      1   1797  0   38 08:20 ?        Ssl    0:00 /usr/sbin/mysqld
mysql      1620      1   1799  0   38 08:20 ?        Ssl    0:00 /usr/sbin/mysqld
mysql      1620      1   1802  0   38 08:20 ?        Ssl    0:00 /usr/sbin/mysqld
mysql      1620      1   1803  0   38 08:20 ?        Ssl    0:00 /usr/sbin/mysqld
mysql      1620      1   1804  0   38 08:20 ?        Ssl    0:00 /usr/sbin/mysqld
mysql      1620      1   1811  0   38 08:20 ?        Ssl    0:00 /usr/sbin/mysqld
mysql      1620      1   1812  0   38 08:20 ?        Ssl    0:05 /usr/sbin/mysqld
mysql      1620      1   1814  0   38 08:20 ?        Ssl    0:00 /usr/sbin/mysqld
mysql      1620      1   1815  0   38 08:20 ?        Ssl    0:00 /usr/sbin/mysqld
mysql      1620      1   1816  0   38 08:20 ?        Ssl    0:00 /usr/sbin/mysqld
mysql      1620      1   1817  0   38 08:20 ?        Ssl    0:00 /usr/sbin/mysqld
mysql      1620      1   1830  0   38 08:20 ?        Ssl    0:00 /usr/sbin/mysqld
mysql      1620      1   1831  0   38 08:20 ?        Ssl    0:00 /usr/sbin/mysqld
mysql      1620      1   1832  0   38 08:20 ?        Ssl    0:00 /usr/sbin/mysqld
mysql      1620      1   1836  0   38 08:20 ?        Ssl    0:00 /usr/sbin/mysqldlwp:线程号

系统会给mysql进程1620分配进程地址空间,内核空间拥有pid1620的pcb。

pid1620进程创建线程时,本身也成了主线程。创建的线程分别拥有自己独立的pcb,处在同一内核空间中。

线程更加节省系统资源,效率不仅可以保持的,而且能够更高在一个地址空间中多个线程独享:每个线程都有属于自己的栈区,寄存器 (内核中管理的)1.线程 id2.处理器现场和栈指针(内核栈)3.独立的栈空间(用户空间栈)4.errno 变量5.信号屏蔽字6.调度优先级在一个地址空间中多个线程共享:代码段,堆区,全局数据区,打开的文件 (文件描述符表) 都是线程共享的1.文件描述符表2.每种信号的处理方式3.当前工作目录4.用户 ID 和组 ID5.内存地址空间 (.text/.data/.bss/heap/共享库)每个进程对应一个虚拟地址空间,一个进程只能抢一个 CPU 时间片一个地址空间中可以划分出多个线程,在有效的资源基础上,能够抢更多的 CPU 时间片一个进程创造线程并不是越多越好优点: 1. 提高程序并发性 2. 开销小 3. 数据通信、共享数据方便
缺点: 1. 库函数,不稳定 2. 调试、编写困难、gdb 不支持 3. 对信号支持不好
优点相对突出,缺点均不是硬伤。Linux 下由于实现方法导致进程、线程差别不是很大。

pthread_self获取当前线程id

获取线程 ID。其作用对应进程中 getpid() 函数。pthread_t pthread_self(void);返回值:成功:0; 失败:无!线程 ID:pthread_t 类型,本质:在 Linux 下为%lu无符号整数,其他系统中可能是结构体实现线程 ID 是进程内部,识别标志。(两个进程间,线程 ID 允许相同)注意:在子线程中通过使用pthread_self,获得线程id。

pthread_create创建线程

创建一个新线程。 其作用对应进程中 fork() 函数。int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);返回值:成功:0; 失败:错误号 -----Linux 环境下,所有线程特点,失败均直接返回错误号。参数:pthread_t:当前 Linux 中可理解为:typedef unsigned long int pthread_t;参数 1:传出参数,保存系统为我们分配好的线程 ID参数 2:通常传 NULL,表示使用线程默认属性。若想使用具体属性也可以修改该参数。参数 3:函数指针,指向线程主函数(线程体),该函数运行结束,则线程结束。参数 4:线程主函数执行期间所使用的参数。传参。

pthread_exit退出当前线程

	void pthread_exit(void *retval);  退出当前线程。参数:线程退出的时候携带的数据,当前子线程的主线程会得到该数据。如果不需要使用,指定为 NULL几个退出函数:exit();	退出当前进程。后续代码不会执行return: 返回到调用者那里去。pthread_exit(): 退出当前线程。不影响其他进程

循环创建线程

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>void *func(void *arg)
{int i = (int)arg;printf("我是第%d子线程线程id:%lu,主线程是:%d\n",i+1,pthread_self(),getpid());//return NULL;if(i==4){while(1);}pthread_exit(NULL);
}int main(int argc, char *argv[])
{pthread_t tid;int i;for(i = 0; i < 5; i++){int ret = pthread_create(&tid,NULL,func,(void*)i);if(ret != 0){perror("pthread_create error");exit(1);}}//sleep(1);printf("我是主线程线程id:%lu,主线程是:%d\n",pthread_self(),getpid());//while(1);//return 0;pthread_exit(NULL);
}
主线程 pthread_exit(NULL);只退出当先线程,不会对其他线程造成影响。
[lc@lc133 pthread]$ gcc pthread.c -lpthread
pthread.c: 在函数‘func’中:
pthread.c:8:10: 警告:将一个指针转换为大小不同的整数 [-Wpointer-to-int-cast]int i = (int)arg;^
pthread.c: 在函数‘main’中:
pthread.c:23:43: 警告:将一个整数转换为大小不同的指针 [-Wint-to-pointer-cast]int ret = pthread_create(&tid,NULL,func,(void*)i);^
[lc@lc133 pthread]$ ./a.out
我是主线程线程id:140307387344704,主线程是:25356
我是第3子线程线程id:140307362223872,主线程是:25356
我是第2子线程线程id:140307370616576,主线程是:25356
我是第1子线程线程id:140307379009280,主线程是:25356
我是第4子线程线程id:140307353831168,主线程是:25356
我是第5子线程线程id:140307345438464,主线程是:25356
[root@lc133 ~]# ps -aux | grep a.out  #使用pthread_exit主线程已退出,子线程还在,使用return函数,主线程退出,子进程也会退出
lc        25356  100  0.0      0     0 pts/1    Zl+  14:51   0:58 [a.out] <defunct>
root      25373  0.0  0.1 112840  2512 pts/0    S+   14:52   0:00 grep --color=auto a.out

pthread_join阻塞 回收线程

int pthread_join(pthread_t thread, void **retval);	阻塞 回收线程。thread: 待回收的线程idretval:传出参数。 回收的那个线程的退出值。线程异常借助,值为 -1。返回值:成功:0失败:errno

pthread_exit可以传出指针,数值,要注意数据格式的强转。

#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <stdlib.h>struct student
{int age;char name[256];
};void *func(void *arg)
{printf("child thread,process id is %d,thread id is %lu\n",getpid(),pthread_self());struct student *luci;luci = malloc(sizeof(struct student));memset(luci,0,sizeof(luci));luci->age = 17;strcpy(luci->name,"luci");pthread_exit((void *)luci);
}int main(int argc, char *argv)
{printf("main thread,process id is %d,thread id is %lu\n",getpid(),pthread_self());pthread_t tid;int ret = pthread_create(&tid,NULL,func,NULL);if(ret != 0){perror("pthread_creade error");exit(1);}struct student *retval;//pthread_join 传出参数retval是void**类型的ret = pthread_join(tid,(void **)&retval);if(ret != 0){perror("pthread_jion error");exit(1);}printf("child thread exit.\n");printf("age = %d ,name = %s \n",retval->age,retval->name);return 0;
}
#include <stdio.h>
#include <pthread.h>void *func(void *arg)
{printf("child pthread id : %lu\n",pthread_self());pthread_exit((void*)66);
}int main(){pthread_t tid;int *retval;pthread_create(&tid,NULL,func,NULL);pthread_join(tid,(void**)&retval) ;printf("main pthread receive : %d\n",(void *)retval);pthread_exit(NULL);
}

pthread_detach 设置线程分离

	int pthread_detach(pthread_t thread);		设置线程分离thread: 待分离的线程id返回值:成功:0失败:errno	
#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <stdlib.h>void *func(void *arg)
{int i;for( i = 0;i < 5; i++){sleep(1);printf("i = %d \n",i);}pthread_exit(NULL);}
int main()
{pthread_t tid;int ret;ret = pthread_create(&tid,NULL,func,NULL);if(ret != 0){fprintf(stderr,"pthread_create error:%d",strerror(ret));exit(1);}pthread_detach(tid);ret = pthread_join(tid,NULL);//线程分离后主线程就不能回收了,报错:无效的参数if(ret != 0){fprintf(stderr,"pthread_join error:%s",strerror(ret));exit(1);}pthread_exit(NULL);return 0;
}

pthread_cancel杀死一个线程

	int pthread_cancel(pthread_t thread);		杀死一个线程。  需要到达取消点(保存点)thread: 待杀死的线程id返回值:成功:0失败:errno在线程 A 中调用线程取消函数 pthread_cancel,指定杀死线程 B,这时候线程 B 是死不了的,只有在线程 B 中进程进行一次系统调用(从用户区切换到内核区),这个节点会被pthread_cancel杀死,否则线程 B 可以一直运行。与信号不同,进程会优先处理信号。如果,子线程没有到达取消点, 那么 pthread_cancel 无效。我们可以在程序中,手动添加一个取消点。使用 pthread_testcancel();成功被 pthread_cancel() 杀死的线程,返回 -1.使用pthead_join 回收。

pthread_equal判断线程id是否相同

	int pthread_equal(pthread_t t1, pthread_t t2);参数:t1 和 t2 是要比较的线程的线程 ID返回值:如果两个线程 ID 相等返回非 0 值,如果不相等返回 0

与进程函数相比

	线程控制原语					进程控制原语pthread_create()				fork();pthread_self()					getpid();pthread_exit()					exit(); 		/ return pthread_join()					wait()/waitpid()pthread_cancel()				kill()pthread_detach()

创建线程时设置线程分离属性

pthread_create函数中参数 pthread_attr_t 是一个结构体

typedef struct
{int                       detachstate;   // 线程的分离状态int                       schedpolicy;   // 线程调度策略structsched_param         schedparam;    // 线程的调度参数int                       inheritsched;  // 线程的继承性int                       scope;         // 线程的作用域size_t                    guardsize;     // 线程栈末尾的警戒缓冲区大小int                       stackaddr_set; // 线程的栈设置void*                     stackaddr;     // 线程栈的位置size_t                    stacksize;     // 线程栈的大小
} pthread_attr_t;
	步骤:pthread_attr_t attr  	创建一个线程属性结构体变量pthread_attr_init(&attr);	初始化线程属性,成功:0;失败:错误号pthread_attr_setdetachstate(&attr,  PTHREAD_CREATE_DETACHED);设置线程属性为 分离态//detachstate: PTHREAD_CREATE_DETACHED(分离线程)//			  PTHREAD _CREATE_JOINABLE(非分离线程)//获取程属性,分离 or 非分离//int pthread_attr_getdetachstate(pthread_attr_t *attr, int *detachstate); //参数: attr:已初始化的线程属性pthread_create(&tid, &attr, tfn, NULL); 借助修改后的 设置线程属性 创建为分离态的新线程pthread_attr_destroy(&attr);	销毁线程属性,成功:0;失败:错误号
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>void *func(void *arg)
{printf("hello wrold.\n");pthread_exit(NULL);
}int main()
{pthread_attr_t attr;pthread_attr_init(&attr);pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);int val;pthread_attr_getdetachstate(&attr,&val);printf("属性:%d\n",val);pthread_t tid;pthread_create(&tid,&attr,func,NULL);pthread_attr_destroy(&attr);sleep(1);int ret = pthread_join(tid,NULL);if(ret != 0){fprintf(stderr,"pthread_join error : %s\n",strerror(ret));exit(1);}pthread_exit(NULL);return 0;
}
[lc@lc pthread]$ ./a.out
属性:1
hello wrold.
pthread_join error : Invalid argument
//pthread_join报错成功分离

注意事项

1. 主线程退出其他线程不退出,主线程应调用 pthread_exit
2. 避免僵尸线程
pthread_join
pthread_detach
pthread_create 指定分离属性
被 join 线程可能在 join 函数返回前就释放完自己的所有内存资源,所以不应当返回被回收线程栈中的值;
3. malloc 和 mmap 申请的内存可以被其他线程释放
4. 应避免在多线程模型中调用 fork 除非,马上 exec,子进程中只有调用 fork 的线程存在,其他线程在子进程
中均 pthread_exit
5. 信号的复杂语义很难和多线程共存,应避免在多线程引入信号机制

相关文章:

5守护进程与线程

进程组 多个进程的集合&#xff0c;第一个进程就是组长&#xff0c;组长进程的PID等于进程组ID。 进程组生存期&#xff1a;进程组创建到最后一个进程离开(终止或转移到另一个进程组)。与组长进程是否终止无关。 一个进程可以为自己或子进程设置进程组 ID 相关函数 pid_t …...

EZ-Cube简易款下载器烧写使用方法

一、硬件连接 跟目标芯片接4根线 VCC、GND、TOOL、REST 四根线&#xff0c;如果板子芯片自己外接电源的&#xff0c;VCC 线可以不接。 二、 安装烧写软件和驱动 烧写软件&#xff1a;https://download.csdn.net/download/Stark_/87444744?spm1001.2014.3001.5503 驱动程序&a…...

sql server安装并SSMS连接

博主简介&#xff1a;原互联网大厂tencent员工&#xff0c;网安巨头Venustech员工&#xff0c;阿里云开发社区专家博主&#xff0c;微信公众号java基础笔记优质创作者&#xff0c;csdn优质创作博主&#xff0c;创业者&#xff0c;知识共享者,欢迎关注&#xff0c;点赞&#xff…...

Python_pytorch (二)

python_pytorch 小土堆pytotch学习视频链接 from的是一个个的包&#xff08;package) import 的是一个个的py文件(file.py) 所使用的一般是文件中的类(.class) 第一步实例化所使用的类,然后调用类中的方法&#xff08;def) Torchvision 数据集 数据集使用&#xff08;CI…...

java手机短信验证,并存入redis中,验证码时效5分钟

目录 1、注册发送短信账号一个账号 2、打开虚拟机&#xff0c;将redis服务端打开 3、创建springboot工程&#xff0c;导入相关依赖 4、写yml配置 5、创建controller层&#xff0c;并创建controller类 6、创建service层&#xff0c;并创建service类 7、创建工具类&#x…...

kubectl命令控制远程k8s集群(Windows系统、Ubuntu系统、Centos系统)

文章目录1. 本地是linux2. 本地是Windows1. 本地是linux 安装kubectl命令 法一&#xff1a;从master的/usr/bin目录下拷贝kubectl文件到本机/usr/bin目录下法二&#xff1a;GitHub下载kubectl文件 在家目录下创建.kube目录config文件 法一&#xff1a;将master上对应用户的~/.…...

【求解器-COPT】COPT的版本更新中,老版本不能覆盖的问题

【求解器-COPT】COPT的版本更新中&#xff0c;老版本不能覆盖的问题方法1方法2如果license还是找不到作者&#xff1a;刘兴禄 参考网址&#xff1a; COPT的下载和配置步骤如下&#xff1a; 教程 | Windows系统下如何安装COPT求解器并配置许可文件&#xff1a; https://zhuan…...

Vue3.0文档整理:一、简介

1.1:什么是vue&#xff1f; Vue是一款用于构建用户界面的javascript框架&#xff1b;它基于标准HTML、CSS和Javascript构建&#xff0c;并提供了一套声明式、组件化的编程模型&#xff0c;帮助你高效的开发用户界面。 1.2&#xff1a;MVVM工作原理 MVVM指的是model、view和vie…...

vue2 diff算法及虚拟DOM

概括&#xff1a;diff算法&#xff0c;虚拟DOM中采用的算法&#xff0c;把树形结构按照层级分解&#xff0c;只比较同级元素&#xff0c;不同层级的节点只有创建和删除操作。 一、虚拟DOM (1) 什么是虚拟DOM&#xff1f; 虚拟 DOM (Virtual DOM&#xff0c;简称 VDOM) 是一种…...

Ray和极客们的创新之作,2月18日来发现

所在论坛&#xff1a;数据库技术创新&云原生论坛分享时段&#xff1a;2.18 10:30-11:00分享主题&#xff1a;云原生数据库PieCloudDB &#xff1a;Unbreakable安全特性剖析分享嘉宾&#xff1a;王淏舟&#xff0c;拓数派资深研发工程师 由中国开源软件推进联盟PostgreSQL分…...

Dubbo 源码分析 – 集群容错之 Router

1. 简介 上一篇文章分析了集群容错的第一部分 – 服务目录 Directory。服务目录在刷新 Invoker 列表的过程中&#xff0c;会通过 Router 进行服务路由。上一篇文章关于服务路由相关逻辑没有细致分析&#xff0c;一笔带过了&#xff0c;本篇文章将对此进行详细的分析。首先&…...

行人检测(人体检测)3:Android实现人体检测(含源码,可实时人体检测)

行人检测(人体检测)3&#xff1a;Android实现人体检测(含源码&#xff0c;可实时人体检测) 目录 行人检测(人体检测)3&#xff1a;Android实现人体检测(含源码&#xff0c;可实时人体检测) 1. 前言 2. 人体检测数据集说明 3. 基于YOLOv5的人体检测模型训练 4.人体检测模型…...

【图像分类】基于PyTorch搭建LSTM实现MNIST手写数字体识别(单向LSTM,附完整代码和数据集)

写在前面: 首先感谢兄弟们的关注和订阅,让我有创作的动力,在创作过程我会尽最大能力,保证作品的质量,如果有问题,可以私信我,让我们携手共进,共创辉煌。 提起LSTM大家第一反应是在NLP的数据集上比较常见,不过在图片分类中,它同样也可以使用。我们以比较熟悉的 mnist…...

Kotlin 1.8.0 现已发布,有那些新特性?

文章目录**如何安装 Kotlin 1.8.0****如果您遇到任何问题****更多文章和视频**结语Kotlin 1.8.0 版本现已发布&#xff0c;以下是其部分最大亮点&#xff1a; JVM 的新实验性功能&#xff1a;递归复制或删除目录内容提升了 kotlin-reflect 性能新的-Xdebug编译器选项&#xff…...

likeshop单商户SaaS商城系统—无限多开,搭建多个商城

likeshop单商户SaaS商城系统&#xff1a;适用于多开&#xff08;SaaS&#xff09;、B2C、单商户、自营商城场景&#xff0c;完美契合私域流量变现闭环交易使用&#xff0c;系统拥有丰富的营销玩法&#xff0c;强大的分销能力&#xff0c;支持DIY多模板&#xff0c;前后端分离。…...

Bean(Spring)的执行流程和生命周期

Bean&#xff08;Spring&#xff09;的执行流程具体的流程就和我们创建Spring基本相似。启动 Spring 容器 -> 实例化 Bean&#xff08;分配内存空间&#xff0c;从无到有&#xff09; -> Bean 注册到 Spring 中&#xff08;存操作&#xff09; -> 将 Bean 装配到需要的…...

工作记录------PostMan自测文件导入、导出功能

工作记录------PostMan自测文件导入、导出功能 测试文件导出 背景&#xff1a;写了一个文件下载功能&#xff0c;是数据写到excel中&#xff0c;下载&#xff0c;使用PostMan点击send后&#xff0c;返回报文是乱码。 解决办法&#xff1a; 点击send下面的 send and Downlo…...

上海亚商投顾:沪指震荡上行 大消费板块全线走强

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。市场情绪三大指数今日震荡反弹&#xff0c;沪指全天低开高走&#xff0c;深成指、创业板指均涨超1%。工程机械板块集体大涨&a…...

linux中的图形化UDP调试工具

sokit freeware version: 1.3.1 (GPLv3) website: https://github.com/sinpolib/sokit/ 这是一个TCP / UDP数据包收发和传输工具 linux汉化 默认是英文版本的&#xff0c;如果想使用中文&#xff0c;把软件目录下的sokit.lan_rename重命令为sokit.lan再次打开软件就发现已经…...

前端react面试题指南

概述下 React 中的事件处理逻辑 抹平浏览器差异&#xff0c;实现更好的跨平台。避免垃圾回收&#xff0c;React 引入事件池&#xff0c;在事件池中获取或释放事件对象&#xff0c;避免频繁地去创建和销毁。方便事件统一管理和事务机制。 为了解决跨浏览器兼容性问题&#xff0…...

JavaSec-RCE

简介 RCE(Remote Code Execution)&#xff0c;可以分为:命令注入(Command Injection)、代码注入(Code Injection) 代码注入 1.漏洞场景&#xff1a;Groovy代码注入 Groovy是一种基于JVM的动态语言&#xff0c;语法简洁&#xff0c;支持闭包、动态类型和Java互操作性&#xff0c…...

微软PowerBI考试 PL300-选择 Power BI 模型框架【附练习数据】

微软PowerBI考试 PL300-选择 Power BI 模型框架 20 多年来&#xff0c;Microsoft 持续对企业商业智能 (BI) 进行大量投资。 Azure Analysis Services (AAS) 和 SQL Server Analysis Services (SSAS) 基于无数企业使用的成熟的 BI 数据建模技术。 同样的技术也是 Power BI 数据…...

【Linux】C语言执行shell指令

在C语言中执行Shell指令 在C语言中&#xff0c;有几种方法可以执行Shell指令&#xff1a; 1. 使用system()函数 这是最简单的方法&#xff0c;包含在stdlib.h头文件中&#xff1a; #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的“no matching...“系列算法协商失败问题

【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的"no matching..."系列算法协商失败问题 摘要&#xff1a; 近期&#xff0c;在使用较新版本的OpenSSH客户端连接老旧SSH服务器时&#xff0c;会遇到 "no matching key exchange method found"​, "n…...

【从零学习JVM|第三篇】类的生命周期(高频面试题)

前言&#xff1a; 在Java编程中&#xff0c;类的生命周期是指类从被加载到内存中开始&#xff0c;到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。本文会深入探寻类的生命周期&#xff0c;让读者对此有深刻印象。 目录 ​…...

Redis:现代应用开发的高效内存数据存储利器

一、Redis的起源与发展 Redis最初由意大利程序员Salvatore Sanfilippo在2009年开发&#xff0c;其初衷是为了满足他自己的一个项目需求&#xff0c;即需要一个高性能的键值存储系统来解决传统数据库在高并发场景下的性能瓶颈。随着项目的开源&#xff0c;Redis凭借其简单易用、…...

FFmpeg:Windows系统小白安装及其使用

一、安装 1.访问官网 Download FFmpeg 2.点击版本目录 3.选择版本点击安装 注意这里选择的是【release buids】&#xff0c;注意左上角标题 例如我安装在目录 F:\FFmpeg 4.解压 5.添加环境变量 把你解压后的bin目录&#xff08;即exe所在文件夹&#xff09;加入系统变量…...

Visual Studio Code 扩展

Visual Studio Code 扩展 change-case 大小写转换EmmyLua for VSCode 调试插件Bookmarks 书签 change-case 大小写转换 https://marketplace.visualstudio.com/items?itemNamewmaurer.change-case 选中单词后&#xff0c;命令 changeCase.commands 可预览转换效果 EmmyLua…...

恶补电源:1.电桥

一、元器件的选择 搜索并选择电桥&#xff0c;再multisim中选择FWB&#xff0c;就有各种型号的电桥: 电桥是用来干嘛的呢&#xff1f; 它是一个由四个二极管搭成的“桥梁”形状的电路&#xff0c;用来把交流电&#xff08;AC&#xff09;变成直流电&#xff08;DC&#xff09;。…...