王道操作系统学习笔记(2)——进程管理

news2024/11/25 23:01:21

前言

本文介绍了操作系统中的进程管理,文章中的内容来自B站王道考研操作系统课程,想要完整学习的可以到B站官方看完整版。

二:进程管理

2.1.1:进程的概念、组成、特征

程序:是静态的,就是存放在磁盘里的可执行文件,就是一系列的指令集合

进程:是动态的,是程序的一次执行过程。同一个程序多次执行会对应多个进程

进程控制块:一个进程中分配了哪些资源、运行情况等信息都会保存在一个数据结构PCB(进程控制块)中,是进程存在的唯一标志,供操作系统使用。

 PCB中所包含的信息:

程序段、数据段、PCB三部分组成了进程实体

进程是进程实体的运行过程,是系统进行资源分配和调度的独立单位,一个进程被调度就是指操作系统决定让这个进程到CPU上运行

2.1.2:进程的状态(运行态、就绪态、阻塞态)与转换、进程的组织

阻塞态:在进程运行过程中,可能会请求等待某个事件的发生(如等待某种系统资源的分配,或者等待其他进程的响应)。在这件事发生之前,进程无法继续往下执行,此时操作系统会让这个进程下CPU,并让他进入“阻塞态”。

终止态:一个进程可以执行exit系统调用,请求操作系统终止该进程。此时该进程会进入“终止态”,操作系统会让该进程下CPU,并回收内存空间等资源,最后还要回收该进程的PCB。

五种状态的切换:

Linux中进程的状态分类:就绪态、运行态、僵尸态、停止态、可中断睡眠状态、不可中断睡眠状态

就绪态(Ready):指该进程满足被 CPU 调度的所有条件但此时并没有被调度执行,只要得到 CPU就能够直接运行;意味着该进程已经准备好被 CPU 执行,当一个进程的时间片到达,操作系统调度程序会从就绪态链表中调度一个进程
运行态:指该进程当前正在被 CPU 调度运行,处于就绪态的进程得到 CPU 调度就会进入运行态;

Zombie(僵尸状态):进程已经结束,但是其父进程还没有调用wait()函数来获取其退出状态,此时进程成为僵尸进程。

Stopped(停止状态):进程被暂停,例如通过Ctrl+Z命令将进程挂起

Interruptible sleep(可中断睡眠状态):进程正在等待某个事件的发生,例如等待输入输出完成或者等待信号量,此时进程可以被中断。

Uninterruptible sleep(不可中断睡眠状态):进程正在等待某个事件的发生,例如等待磁盘I/O操作完成,此时进程不可被中断。

2.1.3:进程通信(共享存储、消息传递、管道通信)

共享存储

共享存储(在内存中开辟一段区域供进程间交换数据,实际是会生成一个文件,在/dev/shm目录下)shm_open、mmap两个函数来实现相关功能,下面通过两个读写文件来展示相关的用法。

write.c:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/mman.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
 
#define MMAP_DATA_SIZE 1024
 
int main(int argc,char* argv[])
{
        char* data;
        int fd = shm_open("shm1", O_CREAT|O_RDWR, 0777);
 
        if (fd < 0) {
                printf("shm_open failed!\n");
                return -1;
        }
 
        ftruncate(fd, MMAP_DATA_SIZE);
        data = (char*)mmap(NULL, 1024, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
        if (!data) {
                printf("mmap failed\n");
                close(fd);
        }

        sprintf(data, "This is a share memory! %d\n", fd);

        munmap(data, MMAP_DATA_SIZE);
 
        close(fd); 
        return 0;
}

read.c:

#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <linux/input.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/mman.h>      
#include <fcntl.h> 

#define  MAP_FILE_SIZE 1024
int main(int argc, char* argv[])
{
    char *data;
    int fd = shm_open("shm1", O_RDONLY, 0777);
    if(fd < 0){
        perror("shm01 open error");
    }
    data = mmap(NULL, MAP_FILE_SIZE, PROT_READ, MAP_SHARED, fd, 0);
    if(data == MAP_FAILED){
        perror("data error");
    }
    printf("open read.c\r\n");
    printf("%s\r\n", data);
    munmap(data, MAP_FILE_SIZE);
    close(fd);

}

两程序的执行结果如下

open和shm_open的主要区别在于它们打开的对象不同,open打开的是普通文件,而shm_open打开的是共享内存对象。

消息传递

消息 = 消息头(发送进程ID、接收进程ID、消息长度)、消息体

消息队列

P通过发送原语send()发送,Q通过接收原语receive()将PCB消息队列的重大的msg拷贝到自己的的地址空间

管道通信 

无名管道:匿名管道是一种无名的管道,只能用于父子进程之间或者兄弟进程之间的通信

代码示例

#include <stdlib.h>
#include <sys/wait.h>
#include <sys/stat.h>


int main(int argc, char *argv[])
{
    //自己写数据到管道,然后从管道中读数据,最后将数据写到标准输出上,终端打印hello
    
    int fd[2];
    int pp = pipe(fd);
    char buf[100];
    for(int i = 0; i < 10; i++){
        write(fd[1], "hello", 5);
        sleep(1);
        int r = read(fd[0], buf, 128);
        write(1, buf, r);
        printf("\r\n");
    }
    close(fd[0]);
    close(fd[1]);
    
    
    //父进程写东西到管道,子进程从管道中读数据,然后打印到终端上
    
    int fd[2];
    int pp = pipe(fd);
    char buf[100];
    if(fork() == 0){
        close(fd[1]);
        for(int i = 0; i < 3; i++){
            int r = read(fd[0], buf, 128);
            //printf("lseek  = %ld\r\n", lseek(fd[0], 0, SEEK_CUR));
            write(1, buf, r);
            printf("\r\n");
        }
        close(fd[0]);
        _exit(0);
    }
    else{
        close(fd[0]);
        for(int i = 0; i < 3; i++){
            write(fd[1], "hello", 5);
            sleep(1);
        }
        wait(NULL);
        close(fd[1]);
        exit(0);
    }
    

}

有名管道:命名管道是一种有名的管道,可以用于任意进程之间的通信

创建有名管道:

    int ret = mkfifo("/tmp/lcdpipe", 0777);
    if(ret < 0){
        perror("!!mkfifo!!");
    }

有名管道读端等待:

 if(fork() == 0){
        //通过管道来接收要执行程序命令,然后执行
        char rec_buf[100];
        int fd = open("/tmp/lcdpipe", O_RDWR);
        read(fd, rec_buf, sizeof(rec_buf));
        printf("receive message\r\n");
        system(rec_buf);
    }

有名管道写端:

 //发送命令回到主界面
            else if((ts_y > 0 && ts_y < 100) && (ts_x > 0 && ts_y <100)){
                char temp2[30]; 
                char command2[30];
                int pid = getpid();
                sprintf(temp2, "%d", pid);
                sprintf(command2, "kill -9 %s", temp2);

                int fd = open("/tmp/lcdpipe", O_RDWR);
                char send_buf[100] = "cd /mnt/udisk && ./mainWindowApp";
                write(fd, send_buf, sizeof(send_buf));
                printf("send message\r\n");
                system(command2);
            }

Linux中的共享内存和管道通信都是进程间通信的方式,但它们之间有以下区别:

1. 共享内存是一种进程间通信的方式,它允许多个进程访问同一块内存区域,而管道通信是一种单向的进程间通信方式,只能在一个方向上传递数据。

2. 共享内存是通过将一段内存区域映射到多个进程的地址空间中来实现的,而管道通信是通过创建一个管道文件来实现的。

3. 共享内存的数据可以直接在内存中进行读写,速度较快,而管道通信需要将数据从一个进程的缓冲区复制到另一个进程的缓冲区中,速度较慢。

2.1.4:线程的概念

线程是一个基本的CPU执行单位,也是程序执行流的最小单位。进程只作为除CPU之外的系统资源的分配单位。

引入线程后的变化

1:系统资源的分配和调度

传统进程机制中,进程是资源分配和调度的的基本单位。引入线程之后进程是资源分配的基本单位,线程是调度的基本单位。

2:并发性

传统进程机制中只能进程间并发,引入线程后,各线程之间也能并发,提升了并发度。

3:系统开销

传统进程间并发,需要切换进程的运行环境,系统开销大。线程间并发,如果是同一进程内的线程切换,则不需要切换进程环境,系统开销小。

线程属性

2.1.5:线程的状态与转换(TCB)

 线程控制块:

线程表:

2.2.1:调度的概念和层次(作业、调度的层次、挂起)

调度的核心理念就是当有一堆任务要处理,但由于资源有限,这些事情没法同时处理。这就需要确定某种规则来决定处理这些任务的顺序。

高级调度(作业调度)

按一定的原则从外存的作业后备队列中挑选一个作业调入内存,并创建进程。每个作业只调入一次,调出一次。作业调入时会建立PCB,调出时才撤销PCB。

 

中级调度(内存调度)

内存不够时,可将某些进程的数据调出外存。等内存空间或者进程需要运行时再重新调入内存。暂时调到外存等待的进程状态为挂起状态。被挂起的进程PCB会被组织成挂起队列

中级调度:按照某种策略决定将哪个处于挂起状态的进程重新的调入内存

低级调度(进程调度)

按照某种策略从就绪队列中选取一个进程,将处理机分配给他

挂起和阻塞的区别:两种状态都是暂时不能获得CPU服务,但挂起状态是将进程映像调到外存去了,而阻塞态下进程映像还在内存中。阻塞态是进程主动等待某个事件的发生,而挂起态是进程被动被中止执行。

三层调度的联系和对比

2.2.2:进程调度的时机和方式(内核临界区、普通临界区、调度时间、抢占式、进程切换)

需要进行进程调度和切换的情况(主动放弃和被迫放弃)

 

不能进行进程切换的情况(处理中断、临界区、原子操作)

内核临界区访问临界资源之前会上锁,如果不尽快释放的话,极有可能影响到操作系统内核的其他管理工作。因此在访问内核程序临界区期间不能进行调度和切换。普通临界区访问的临界资源不会直接影响操作系统内核的管理工作。因此在访问普通临界区的时候可以进行调度和切换。

非抢占式:只允许进程主动放弃处理机,在运行过程中即便有更紧迫的任务到达,当前进程依然会继续使用处理机,直到该进程终止和主动要求进入阻塞态。

抢占式:当一个进程正在处理机上执行时,如果有一个更重要或更紧迫的进程需要使用处理机,则立即暂停正在执行的过程,将处理机分配给更重要紧迫的那个进程。

进程切换:是指一个进程让出处理机,由另一个进程占用处理机的的过程。进程切换主要完成了对原来运行进程的各种数据保存,对新的进程各种数据的恢复。(如:程序计数器、程序状态字等,这些信息一般保存在进程控制块PCB中)

2.2.3:调度器和闲逛进程

 当没有其他就绪进程时,调度程序就会运行闲逛进程(idle)

2.2.4:调度算法的评价指标(CPU利用率、系统吞吐量、周转时间、等待响应时间)

CPU利用率:CPU“忙碌”的时间占总时间的比例

系统吞吐量:单位时间内完成的作业数量

周转时间:是指从作业被提交给系统开始,到作业完成为止的这段时间间隔

周转时间包括四部分:作业在外存后备队列上等待作业调度(高级调度)的时间+进程在就绪队列上等待进程调度(低级调度)的时间+进程在CPU上执行的时间+进程等待I/O操作完成的时间

2.2.5:调度算法(FCFS、SJF、HRRN、时间片轮转、优先级调度)

1、先来先服务:

饥饿现象:某进程/作业长期得不到某种资源或服务

FCFS的优缺点:对长作业有利,对短作业不利(食堂打饭时前面有个人给全宿舍的人带饭)

2、短作业优先算法:

追求最少的平均等待时间,最少的平均周转时间

3、高响应比优先算法:

要综合考虑作业/进程的等待时间和要求服务的时间

响应比 = (等待时间 + 要求服务的时间)/ 要求服务的时间

4、时间片轮转:

公平地、轮流地为各个进程服务,让每个进程在一定时间间隔内都可以得到响应。如果时间片太大,使得每个进程都可以在一个时间片内就完成,则时间片轮转调度算法退化为先来先服务调度算法,并且会增大进程响应时间。另一方面如果时间片太小,进程调度和切换有时间代价的(保存、恢复运行环境),如果时间片太小,会导致进程切换过于频繁,系统会花大量的时间来处理进程切换,从而导致实际用于进程执行的时间比例减小。

5、优先级调度算法:

可能会导致低优先级进程饥饿

2.3.1:进程同步和互斥

进程互斥软件实现(单标志法、双标志先检查法)

单标志法:

缺点:自己访问完临界资源之后,一定要等另一个人用一次临界资源自己才可以继续使用。如果人家不用自己也不能再用。

双标志先检查法:(类似于上锁和解锁)

缺点:当两个进程并发运行时,若flag[0]未置为true,P1就执行到了flag[1] = true,那么两个进程都会访问临界区资源,违反了“忙则等待”的原则。

双标志后检查法:

缺点:会导致各个进程都无法访问临界资源而产生“饥饿”现象,谁都用不了

皮特森算法(Peterson)

核心思想:主动争取、主动谦让、检查对方是否也想用,且最后一次是不是自己说了“客气话”,谁最后说了“客气话”就会失去优先权。

2.3.3:进程互斥硬件实现(中断屏蔽、TSL、SWAP)

1:中断屏蔽方法

优点:简单、高效

缺点:不适用于多处理机;只适用于操作系统内核进程,不适用于用户进程(因为开/关中断指令只能运行在内核态,这组指令如果让用户随意使用就会很危险)

2:TestAndSet指令(硬件实现)

TSL指令把“上锁”、“检查”操作用硬件的方式变成了一气呵成的原子操作。

缺点:不满足“让权等待”原则,暂时无法进入临界区的进程会占用CPU并循环执行TSL命令,从而导致“忙等”。

3:SWAP命令(硬件实现)

缺点:不满足“让权等待”原则,暂时无法进入到临界区的进程会占用CPU并循环执行TSL指令,从而导致“忙等”。

2.3.4:互斥锁

特性:

1:需要忙等,进程时间片用完后才下处理机,违反“让权等待”

2:等待期间不用切换进程,多处理器系统中,若上锁的时间短,则等待代价低

3:常用于多处理器系统,一个核等,其他核照常工作,并快速释放临界区

4:不太适用于单处理机系统,忙等的过程中不可能解锁(在那个时间片内)。

2.3.5:信号量机制(整型信号量、记录型信号量)

进程实现互斥(软件、硬件)方式存在的问题

1:双标志先检查法中,进入“检查”、“上锁”操作无法一气呵成,从而导致了两个进程有可能同时进入临界区的问题。

2:所有的解决方案都无法实现“让权等待”。

整型信号量:(原子操作但是不满足“让权等待”原则)

用一个整数型的变量作为信号量,用来表示系统中某种资源的数量,与普通整数型变量的区别,对信号量的操作只有三种(初始化、P操作、V操作)

记录型信号量: 

2.3.6:生产者-消费者问题(单生产者-单消费者)

实现互斥的P操作一定要在实现同步的P操作之后,V操作不会导致进程阻塞,因此两个V操作的顺序可以交换

P操作不要轻易换位置,当empty = 0或者full = 0时都会造成两个进程相互等待,导致死锁。 

2.3.7:多生产者、多消费者问题(多种类型)

2.3.8:吸烟者问题(单生产者-多消费者)

2.3.9:读者-写者问题

要求

1:同一时间允许多个读者可以同时对文件执行读操作

2:同一时间只允许一个写者往文件中写信息

3:任意写者在完成写操作之前不允许其他读者或写者工作

4:写者执行写操作前应让已有的读者和写者全部退出

读进程优先,读进程之间不互斥,核心就在count这个变量

在最后一个读进程完成之前,写进程都不能上处理机执行,可能发生“饿死”现象的版本

 写进程解决饥饿的版本,增加了一个互斥信号量

2.3.10:哲学家进餐问题(进程死锁)

2.4.1:死锁基本概念(死锁四个基本条件)

死锁:在并发环境下,各进程因竞争资源而造成的一种互相等待对方手里的资源,导致各进程都阻塞,都无法向前推进的现象。

饥饿:由于长期得不到想要的资源,某进程无法向前推进的现象

死循环:某进程执行过程中一直跳不出某个循环的现象

死锁产生的四个必要条件

1:互斥条件:只有对必须互斥使用的资源的争抢才会导致死锁(哲学家的筷子),内存、扬声器这样可以同时对多个进程使用的资源是不会死锁的。

2:不剥夺条件:进程在获得的资源在未使用完之前,不能由其他进程强行夺走,只能主动释放。

3:请求和保持条件:进程现在已经持有了至少一个资源,但又提出了新资源的请求,而新资源又被其他进程占有;但又对自己已持有的资源不放手

4:循环等待条件:存在一种进程资源的循环等待链,链中的每一个进程已获得的资源同时被下一个进程所请求。

2.4.2:预防死锁(破坏死锁的四条件其中之一)、避免死锁、检测和解除、银行家算法

安全序列:指如果系统按照这种序列分配资源,则每个进程都能顺利完成,只要能找出一个安全序列,系统就是安全状态。如果系统进入不安全状态,就可能发生死锁。

银行家算法:

 

总结

以上是本文的全部内容,非常感谢你能看到这。

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

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

相关文章

【好书精读】网络是怎样连接的 —— UDP 协议的收发操作

&#xff08; 该图由我使用 AI 绘制 &#xff09; 目录 不需要重发的数据用 UDP 发送更高效 控制用的短数据 音频和视频数据 不需要重发的数据用 UDP 发送更高效 DNS 服务器查询 IP 地址的时候我们用的是 UDP 协议 简单的说就是&#xff0c;TCP之所以复杂&#xff0c;是…

3-css高级特效-1

01-平面转换 简介 作用&#xff1a;为元素添加动态效果&#xff0c;一般与过渡配合使用 概念&#xff1a;改变盒子在平面内的形态&#xff08;位移、旋转、缩放、倾斜&#xff09; 平面转换也叫 2D 转换&#xff0c;属性是 transform 平移 transform: translate(X轴移动距…

Jetpack Compose 入门难点解疑

作者&#xff1a;晴天小庭 近些年声明式布局开发方式逐渐从网页端延展到了手机端&#xff0c;说到底还是声明式太香了&#xff0c;其代码更加清晰、简洁&#xff0c;并且更接近于自然语言的表达方式。这使得代码易于理解和维护&#xff0c;降低了开发人员的心智负担。 谷歌和苹…

【c语言12】字符串函数(strlen,strcmp,strcpy,strcat,strstr,strtok,strerror)

文章目录 一、字符串函数1.1strlen&#xff08;求字符串长度&#xff09;1.2strcmp&#xff08;比较字符串&#xff09;1.3strcpy&#xff08;拷贝字符串&#xff09;1.4strcat&#xff08;追加字符串&#xff09;1.5strstr&#xff08;判断子串&#xff09;1.6sttok&#xff0…

【C/C++】使用类和对象 封装链表

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞 关注支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; &#x1f525;c系列专栏&#xff1a;C/C零基础到精通 &#x1f525; 给大…

SpringMVC全套详解

1、SpringMVC是什么1.1、MVC定义1.2、MVC和 SpringMVC的关系2.创建SpringMVC项目 2.1、SpringMVC 链接2.2、RequestMapping 注解说明2.3 、 GetMapping 和 PostMapping 3、获取参数3.1、传递单个参数3.2、传递多个参数/表单参数传递3.3、传递对象3.4、后端参数重命名(后端参数映…

C语言笔记-1

文章目录 C 基础语法注意 C 其他知识点编译过程编译器数据模型区别32/64位机器中&#xff0c;各数据类型所占位数assert() 断言&#xff08;宏&#xff09;用法总结与注意事项 C 基础语法 注意 if(a表达式) 判断的就是a的值&#xff0c;而不是判断这个赋值操作的成功与否。 查…

老天如果给我一次重来的机会,我还会选测试

在我们选择测试这行前&#xff0c;想象总是美好&#xff0c;然而现实无比扎心。 在办公环境上 想象中&#xff1a;美女&#xff08;帅哥&#xff09;环绕&#xff0c;前卫时尚&#xff0c;拥有独立办公间&#xff0c;没事转转座椅&#xff0c;偶尔来点咖啡和音乐。 现实中&…

【数据结构与算法C++实现】2、二分查找

原视频为左程云的B站教学 1 在有序数组中查找特定元素 基本思想是通过比较中间元素与目标元素的大小关系&#xff0c;将查找范围缩小一半&#xff0c;直到找到目标元素或查找范围为空为止。 时间复杂度O(logN) 因为比如说数组个数为N16, 最差的情况要分 4 次 ( [ 8 ∣ 8 ] →…

变化太快的Roop项目(版本1.0.1)

文章目录 &#xff08;一&#xff09;版本1.0.1的变化&#xff08;1.1&#xff09;项目依赖&#xff08;1.2&#xff09;模型位置&#xff08;1.3&#xff09;命令行&#xff08;1.4&#xff09;界面UI&#xff08;1.5&#xff09;处理与结果 最早的&#x1f517;接触和介绍&am…

带三维重建和还原功能的医学影像管理系统(pacs)源码

一、概述 它集影像存储服务器、影像诊断工作站及RIS报告系统于一体,主要由图像处理模块、影像数据管理模块、RIS报告模块、光盘存档模块、DICOM通讯模块、胶片打印输出等模块组成&#xff0c; 具有完善的影像数据库管理功能&#xff0c;强大的图像后处理功能&#xff08;三维重…

2-css-3

一 选择器 1 结构伪类选择器 作用&#xff1a;根据元素的结构关系查找元素。 选择器说明E:first-child查找第一个E元素E:last-child查找最后一个E元素E:nth-child(N)查找第N个E元素&#xff08;第一个元素N值为1&#xff09; li:first-child {background-color: green; }2 :…

AgilePLM应用周期性崩溃-问题解决

​ 问题现象 每周六2点左右&#xff0c;AgilePLM应用进程都会崩溃&#xff0c;具体表现为登录Agile应用服务器之后&#xff0c;找不到weblogic应用进程&#xff08;ps -ef | grep java&#xff09;。从服务器所有相关日志中没有找到任何可疑的异常日志。 当天Agile应用重启之…

UDS通信服务解析

InputOutputControlByIdentifier (0x2F)----通过ID对输入输出进行控制 2F的03子功能是"暂时接管控制权" ReadDataByIdentifier(0x2A)—通过ID读取数据或特定器件状态 ClearDiagnosticInformation(0x14)—清除故障诊断信息 UDS规定用FF FF FF表示所有种类的DTC Rou…

技术干货 | 开始使用 Redis

Redis 是一个使用 C 语言编写的开源、BSD 许可、高级的键值存储&#xff0c;。它也被称为数据结构服务器&#xff0c;因为键可以包含字符串、哈希、列表、集合和有序集合。本教程将介绍使用 Redis 所需的基本概念。Navicat Premium 和 Navicat for Redis 现已支持 Redis, 如果你…

【AUTOSAR】AUTOSAR开发工具链(十一)----基于BTC的back to back测试操作说明(3)

四、PowerWindow demon BTB测试 1、对于MBD生成代码&#xff0c;可以通过上文中使用Embeded-Coder的方式添加工程文件&#xff0c;然后切换到back to back 测试模式 2、点击Generate Stimuli Vectors &#xff0c;进入自动生成测试用例 选择测试用例的生成引擎 设置信号的使用…

2021年国赛高教杯数学建模D题连铸切割的在线优化解题全过程文档及程序

2021年国赛高教杯数学建模 D题 连铸切割的在线优化 原题再现 连铸是将钢水变成钢坯的生产过程&#xff0c;具体流程如下&#xff08;图 1&#xff09;&#xff1a; 钢水连续地从中间包浇入结晶器&#xff0c;并按一定的速度从结晶器向下拉出&#xff0c;进入二冷段。钢水经过…

js中几种实用的跨域方法原理详解

一、通过jsonp跨域 在js中&#xff0c;我们直接用XMLHttpRequest请求不同域上的数据时&#xff0c;是不可以的。但是&#xff0c;在页面上引入不同域上的js脚本文件却是可以的&#xff0c;jsonp正是利用这个特性来实现的。 比如&#xff0c;有个a.html页面&#xff0c;它里面…

微服务系列文章之 Springboot集成Jersey

​ Springboot支持Jersey1.x和Jersey2.x&#xff0c;我们这里只介绍Springboot对Jersey2.x的支持。springboot对jersey的集成非常简单。 ​ 项目结构&#xff1a; 1、引入Springboot对Jersey的starter包 <dependencies><dependency><groupId>org.springfram…

(一)python实战——使用Pyinstaller打包一个python的exe可执行文件

前言 在python编程中&#xff0c;我们往往需要将我们的应用程序打包成一个可执行文件&#xff0c;方便使用。如果是单独的python文件&#xff0c;其他人使用前必须要先安装python环境&#xff0c;在python环境中通过命令执行我们的python程序。本节内容我们主要介绍一下使用Py…