Linux系统认知——驱动认知
文章目录
- 一、驱动相关概念
- 1.什么是驱动
- 2.被驱动设备分类
- 3.设备文件的主设备号和次设备号
- 4.设备驱动整体调用过程
- 二、基于框架编写驱动代码
- 1.驱动代码框架
- 2.驱动代码的编译和测试
- 三、树莓派I/O口驱动的编写
- 1.微机的总线地址、物理地址、虚拟地址介绍
- 2.通过树莓派芯片手册确定需要配置的寄存器
- 3.根据驱动框架编写树莓派Pin4引脚的驱动
一、驱动相关概念
1.什么是驱动
Linux内核驱动:是指一段代码,这段代码可以驱动底层硬件,即驱动就是对底层硬件设备的操作进行封装,并向上层提供函数接口。
2.被驱动设备分类
- 字符设备:
指只能一个字节一个字节读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先后顺序。字符设备是面向流的设备,常见的字符设备有鼠标、键盘、串口、控制台和LED设备等,字符设备驱动程序通常至少要实现open、close、read和write的系统调用,字符终端(/dev/console)和串口(/dev/ttyS0以及类似设备)就是两个字符设备,它们能很好的说明“流”这种抽象概念。 - 块设备:
指可以从设备的任意位置读取一定长度数据的设备。块设备包括硬盘、磁盘、U盘和SD卡等。 - 网络设备:
网络设备可以是一个硬件设备,如网卡; 但也可以是一个纯粹的软件设备, 比如回环接口(lo).一个网络接口负责发送和接收数据报文。
3.设备文件的主设备号和次设备号
Linux的设备管理是和文件系统紧密结合的,各种设备都以文件的形式存放在/dev目录下,称为设备文件,应用程序可以打开、关闭和读写这些设备文件,完成对设备的操作,就像操作普通的数据文件一样。为了管理这些设备,系统为设备编了号,每个设备号又分为主设备号和次设备号。主设备号用来区分不同种类的设备,而次设备号用来区分同一类型的多个设备。
一个字符设备或者块设备都有一个主设备号和次设备号。主设备号和次设备号统称为设备号。主设备号用来表示一个特定的驱动程序。次设备号用来表示使用该驱动程序的各设备。例如一个嵌入式系统,有两个LED指示灯,LED灯需要独立的打开或者关闭。那么,可以写一个LED灯的字符设备驱动程序,可以将其主设备号注册成5号设备,次设备号分别为1和2。这里,次设备号就分别表示两个LED灯。
设备文件通常都在 /dev 目录下。
设备号的作用:
在内核空间中,存在一个驱动链表管理所用设备的驱动。驱动链表主要有两个功能,分别为添加(编写完驱动程序,加载到内核)功能和查找(调用驱动程序)功能。在这些过程中,驱动插入链表的顺序由设备号检索,这便是设备号的主要作用。
4.设备驱动整体调用过程
(1)C语言上层调用open函数。open(“dev/pin4”,O_RDWR);调用/dev下的pin4以可读可写的方式打开。对于上层open调用到内核时会发生一次软中断中断号是0X80,从用户空间进入到内核空间
(2)open会调用到system_call(内核函数),system_call会根据/dev/pin4设备名,去找出需要的设备号。
(3)再调到虚拟文件VFS ,调用VFS里的sys_open,sys_open会找到在驱动链表里面,根据主设备号和次设备号找到引脚4里的open函数,引脚4里的open是对寄存器操作及对硬件的操作。
二、基于框架编写驱动代码
1.驱动代码框架
#include <linux/fs.h> //file_operations声明#include <linux/module.h> //module_init module_exit声明
#include <linux/init.h> //__init __exit 宏定义声明
#include <linux/device.h> //class devise声明
#include <linux/uaccess.h> //copy_from_user 的头文件
#include <linux/types.h> //设备号 dev_t 类型声明
#include <asm/io.h> //ioremap iounmap的头文件static struct class *pin4_class;
static struct device *pin4_class_dev;static dev_t devno; //设备号
static int major =231; //主设备号
static int minor =0; //次设备号
static char *module_name="pin4"; //模块名static int pin4_open(struct inode *inode,struct file *file)
{printk("pin4_open\n"); //内核的打印函数和printf类似return 0;
}static ssize_t pin4_write(struct file *file,const char __user *buf,size_t count, loff_t *ppos)
{printk("pin4_write\n");return 0;
}
static struct file_operations pin4_fops = {.owner = THIS_MODULE,.open = pin4_open,//当应用层调用open函数时,内核会调用pin4_open..write = pin4_write,//当应用层调用write函数时,内核会调用pin4_write.
};int __init pin4_drv_init(void) //真实的驱动入口
{int ret;devno = MKDEV(major,minor); //创建设备号ret = register_chrdev(major, module_name,&pin4_fops); //注册驱动 告诉内核,把这个驱动加入到内核驱动的链表中pin4_class=class_create(THIS_MODULE,"myfirstdemo");//由代码在dev下自动生成设备pin4_class_dev =device_create(pin4_class,NULL,devno,NULL,module_name); //创建设备文件return 0;
}void __exit pin4_drv_exit(void)
{device_destroy(pin4_class,devno);class_destroy(pin4_class);unregister_chrdev(major, module_name); //卸载驱动}module_init(pin4_drv_init); //入口
module_exit(pin4_drv_exit);
MODULE_LICENSE("GPL v2");`
2.驱动代码的编译和测试
(1)进入Linux源码树目录下的驱动目录,因为驱动的是字符设备,所以进入的是驱动目录下的char目录。/home/zh/SYSTEM/linux-rpi-4.14.y/drivers/char
(2)将驱动代码放到上述目录下
(3)修改Makefile文件
在字符驱动目录下 打开Makefile文件,并以模块的方式将驱动载入:
(4)模块编译
进入源码树目录进行模块化编译,键入
ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- KERNEL=kernel7 make modules
(5)将编译好的驱动模块传到树莓派中
scp ./drivers/char/pin4driver.ko pi@192.168.169.221:/home/pi
加载内核驱动模块,在dev/目录下生成pin4驱动
sudo insmod pin4driver.kormmod pin4driver.ko //卸载驱动模块
(6)给pin4驱动加权限
sudo chmod 666 /dev/pin4
(7)驱动程序测试
pin4test.c
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char const *argv[])
{/* code */int fd;fd = open("/dev/pin4",O_RDWR);write(fd,"hello",strlen("hello"));return 0;
}
执行测试程序后用dmesg 查看内核打印信息发现打印了驱动函数的内容
三、树莓派I/O口驱动的编写
这里以驱动树莓派pin4引脚置0或置1为例。
1.微机的总线地址、物理地址、虚拟地址介绍
(1)总线地址
地址总线(Address Bus)是一种计算机总线,是CPU或有DMA能力的单元,用来沟通这些单元想要访问(读取/写入)计算机内存组件/地方的物理地址。
地址总线决定了cpu所能访问的最大内存空间的大小,即cpu能访问的内存范围。
比如:装了32位的win 7 系统,内存8G,可系统最大只能识别3.29G,所以要使用4G以上大内存就要用windows x64位系统。装了32位的操作系统CPU的访问范围是2^32 bit,就是4194304kbit,就是4G。树莓派也是32位 ,一个G的内存,但它只能访问949M,剩下的另作他用。
(2)物理地址
在存储器里以字节为单位存储信息,为正确地存放或取得信息,每一个字节单元给以一个唯一的存储器地址,称为物理地址(Physical Address),又叫实际地址或绝对地址。
物理地址它是在地址总线上,以电子形式存在的,使得数据总线可以访问主存的某个特定存储单元的内存地址。在和虚拟内存的计算机中,物理地址这个术语多用于区分虚拟地址。尤其是在使用内存管理单元(MMU)转换内存地址的计算机中,虚拟和物理地址分别指在经MMU转换之前和之后的地址。
(3)虚拟地址
虚拟地址顾名思义即为逻辑地址(基于算法的地址)。
CPU启动保护模式后,程序运行在虚拟地址空间中。注意,并不是所有的“程序”都是运行在虚拟地址中。CPU在启动的时候是运行在实模式的,Bootloader以及内核在初始化页表之前并不使用虚拟地址,而是直接使用物理地址的。
如果CPU寄存器中的分页标志位被设置,那么执行内存操作的机器指令时,CPU(准确来说,是MMU,即Memory Management Unit,内存管理单元)会自动根据页目录和页表中的信息,把虚拟地址转换成物理地址,完成该指令。
使用了分页机制之后,4G的地址空间被分成了固定大小的页,每一页或者被映射到物理内存,或者被映射到硬盘上的交换文件中,或者没有映射任何东西。对于一般程序来说,4G的地址空间,只有一小部分映射了物理内存,大片大片的部分是没有映射任何东西。物理内存也被分页,来映射地址空间。
2.通过树莓派芯片手册确定需要配置的寄存器
在BCM2835芯片手册的第六章描述了General Purpose I/O (GPIO)外设相关寄存器。
这里驱动pin4引脚需要用到的寄存器有:
1.GPIO Function Select Registers (GPFSELn) 功能选择寄存器:
该寄存器共有五组,每个寄存器都有32位,以GPIO Alternate function select register 0为例,其中:
29-0位 :每三位对于一个引脚,比如29-27对应的是GPIO Pin 9,26-24对应的是GPIO Pin 8,且这三位取不同的值代表该三位对应的引脚选择不同的功能。比如,当29-27位为000时表示GPIO Pin 9是输入功能,29-27位为001时表示GPIO Pin 9是输出的功能。
2.GPIO Pin Output Set Registers (GPSETn) 置位寄存器:
该寄存器共两组,每个寄存器都有32位,将寄存器某一位置1即将对应的引脚置1。
3.GPIO Pin Output Clear Registers (GPCLRn) 清0寄存器:
与置位寄存器用法一至,将对应位数引脚置0.
4.所需寄存器的地址说明
在编写驱动程序时,IO空间的起始地址位0X3F000000,加上GPIO的偏移量0X200000,因此GPIO的物理地址是从0X3F200000开始的,而编程所需的地址是虚拟地址,需要通过MMU内存虚拟化管理将地址映射到虚拟地址上
3.根据驱动框架编写树莓派Pin4引脚的驱动
驱动代码
pin4driver.c
#include <linux/fs.h> //file_operations声明
#include <linux/module.h> //module_init module_exit声明
#include <linux/init.h> //__init __exit 宏定义声明
#include <linux/device.h> //class devise声明
#include <linux/uaccess.h> //copy_from_user 的头文件
#include <linux/types.h> //设备号 dev_t 类型声明
#include <asm/io.h> //ioremap iounmap的头文件static struct class *pin4_class;
static struct device *pin4_class_dev;static dev_t devno; //设备号
static int major =231; //主设备号
static int minor =0; //次设备号
static char *module_name="pin4"; //模块名//首先定义所要用的寄存器,为了防止地址被编译器优化需要用到volatile关键字
volatile unsigned int *GPFSEL0 = NULL;
volatile unsigned int *GPSET0 = NULL;
volatile unsigned int *GPCLR0 = NULL;static int pin4_open(struct inode *inode,struct file *file)
{printk("pin4_open\n"); //内核的打印函数和printf类似//配置引脚4的寄存器,将其配置为输出模式,即将GPFSEL0寄存器的第14-12位配置成001*GPFSEL0 &= 0XFFFF9FFF; //将第14,13位置0*GPFSEL0 |= 0X00001000; //将第12位置1return 0;
}static ssize_t pin4_write(struct file *file,const char __user *buf,size_t count, loff_t *ppos)
{int usercmd;printk("pin4_write\n");copy_from_user(&usercmd,buf,count);//获取应用层write函数写入的内容if(usercmd == 1){printk("set 1\n");*GPSET0 |=(0x1 << 4); //将Pin4引脚置1}else if (usercmd == 0){printk("set 0\n");*GPCLR0 |=(0X1 << 4);//将Pin4引脚置0}else{printk("undo\n");}return 0;
}static struct file_operations pin4_fops = {.owner = THIS_MODULE,.open = pin4_open,//当应用层调用open函数时,内核会调用pin4_open..write = pin4_write,//当应用层调用write函数时,内核会调用pin4_write.
};int __init pin4_drv_init(void) //真实的驱动入口
{int ret;devno = MKDEV(major,minor); //创建设备号ret = register_chrdev(major, module_name,&pin4_fops); //注册驱动 告诉内核,把这个驱动加入到内核驱动的链表中pin4_class=class_create(THIS_MODULE,"myfirstdemo");//由代码在dev下自动生成设备pin4_class_dev =device_create(pin4_class,NULL,devno,NULL,module_name); //创建设备文件GPFSEL0 = (volatile unsigned int *)ioremap(0X3f200000,4);//需要将物理地址映射位虚拟地址 ipremap第一个参数需要被映射的物理地址。第二个参数位映射的字节数GPSET0 = (volatile unsigned int *)ioremap(0X3f20001C,4);//通过芯片手册可以看到该寄存器在基础地址上偏移了1CGPCLR0 = (volatile unsigned int *)ioremap(0X3f200028,4);//通过芯片手册可以看到该寄存器在基础地址上偏移了28return 0;
}void __exit pin4_drv_exit(void)
{iounmap(GPFSEL0);iounmap(GPSET0);iounmap(GPCLR0);device_destroy(pin4_class,devno);class_destroy(pin4_class);unregister_chrdev(major, module_name); //卸载驱动
}module_init(pin4_drv_init); //入口
module_exit(pin4_drv_exit);
MODULE_LICENSE("GPL v2");
测试代码():
pin4test.c
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char const *argv[])
{int fd,cmd;fd = open("/dev/pin4",O_RDWR);printf("inout 0 ro 1 , 0 :Pin4 Set 0,1:Pin4 Set 1\n");scanf("%d",&cmd);printf("cmd = %d \n",cmd);write(fd,&cmd,1);return 0;
}
将驱动代码编译后生成驱动模块放置在树莓派上进行测试
ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- KERNEL=kernel7 make modules
将生成的驱动模块拷贝至树莓派
scp ./drivers/char/pin4driver.ko pi@192.168.66.221:/home/pi
在树莓派上安装驱动并给驱动权限
sudo insmod pin4driver.ko
sudo chmod 666 /dev/pin4
运行测试程序:
相关文章:
Linux系统认知——驱动认知
文章目录一、驱动相关概念1.什么是驱动2.被驱动设备分类3.设备文件的主设备号和次设备号4.设备驱动整体调用过程二、基于框架编写驱动代码1.驱动代码框架2.驱动代码的编译和测试三、树莓派I/O口驱动的编写1.微机的总线地址、物理地址、虚拟地址介绍2.通过树莓派芯片手册确定需要…...
Spring boot装载模板代码并自动运行
Spring boot装载模板代码涉及的子模块及准备省心Clickhouse批量写JSON多层级数据自动映射值模板代码生成及移交控制权给Spring IOC涉及的子模块及准备 最近比较有空,之前一直好奇,提交到线上考试的代码是如何执行测试的,在实现了基础的demo后…...
全国领先——液力悬浮仿生型人工心脏上市后在同济医院成功植入
2023年2月22日,华中科技大学同济医学院附属同济医院(同济医院)心脏大血管外科团队举办了一场气氛热烈的小规模庆祝活动,魏翔主任、程才副主任、王星宇副主任医师和李师亮医师到场,为终末期心衰患者黄先生“庆生”&…...
基于蚂蚁优化算法的柔性车间调度研究(Python代码实现)
👨🎓个人主页:研学社的博客💥💥💞💞欢迎来到本博客❤️❤️💥💥🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密…...
云原生周刊:开源漏洞仍然是开发人员面临的挑战 | 2023.2.27
Synopsys 发布了最新一期的开源安全年度报告,开源安全和风险分析 (OSSRA)。这份报告由Synopsys 网络安全研究中心 (CyRC)创建,着眼于 Black Duck 审计服务团队进行的 1,700 多次商业代码库审计的结果。 自 2019 年以来,OSSRA 所有 17 家企业…...
Docker学习总结
1、镜像操作 1.1 拉取、查看镜像 步骤一: 首先去镜像仓库搜索nginx镜像,比如[DockerHub]( Docker Hub Container Image Library | App Containerization ) : 步骤二: 根据查看到的镜像名称,拉取自己需要的镜像 通过命令&…...
Android 9.0系统源码_通知服务(三)应用发送状态栏通知的流程
前言 应用发送一个显示在状态栏上的通知,对于移动设备来说是很常见的一种功能需求,本篇文章我们将会结合Android9.0系统源码具体来分析一下,应用调用notificationManager触发通知栏通知功能的源码流程。 一、应用触发状态栏通知 应用可以通…...
python中的序列——笔记
一、介绍 ABC语言时一个致力于为初学者设计编程环境的长达十年的研究项目。 Python也从ABC那里继承了用统一的风格去处理序列数据这一特点。不管是哪种数据结构,字符串、列表、字节序列、数组、XML元素,抑或是数据库查询结果,它们都共用一套…...
taobao.user.seller.get( 查询卖家用户信息 )
¥开放平台基础API必须用户授权 查询卖家用户信息(只能查询有店铺的用户) 只能卖家类应用调用。 公共参数 请求地址: HTTP地址 http://gw.api.taobao.com/router/rest 公共请求参数: 公共响应参数: 请求参数 点击获取key和secret请求示例…...
WebRTC Qos策略
1.WebRTC 用于提升 QoS 的方法:NACK、FEC、SVC、JitterBuffer、IDR Request、PACER、Sender Side BWE、VFR(动态帧率调整策略)https://blog.csdn.net/CrystalShaw/article/details/80432267丢包重传NACK:一种通知技术,…...
Mysql数据查询
文章目录1 group by子句2 回溯统计3 having子句1 group by子句 group by子句**:分组统计,根据某个字段将所有的结果分类,并进行数据统计分析 分组的目的不是为了显示数据,一定是为了统计数据group by子句一定是出现在where子句之…...
Kafka入门(五)
下面聊聊Kafka常用命令 1、Topic管理命令 以topic:test_1为例 1.1、创建topic ./bin/kafka-topics.sh --create --bootstrap-server localhost:9092 --replication-factor 3 --partitions 3 --topic test_1参数说明: –bootstrap-server:…...
如何快速在windows系统中切换node.js版本
前言 最近在同时维护公司的两个项目,一个是新项目,另一个是老项目,二者所依赖的node版本是不一致的。 这就导致我在切换项目的时候必须重新安装对应版本的 node.js,否则就会报各种神马错误。 但这一卸一装可着实烦死个银…...
设计模式-单例模式(java)
单例是一种常用的设计模式,它的目的是确保一个类只有一个实例,并提供一个全局访问点。在Java编程语言中,实现单例有多种方法,本篇文章将介绍其中的两种实现方式。 方式一:饿汉式单例模式 饿汉式单例模式是最简单的实…...
Revit中复合墙图层的规则和CAD识别翻模墙
一、Revit中用于指定复合墙图层的规则,具体内容? 在编辑复合墙的结构时,请使用“指定图层”工具将“编辑部件”对话框中的行指定给图层或预览窗格中的区域,并遵循这些原则。 在预览窗格中,样本墙的各个行必须保持从左到右的顺序显…...
【DL】Paddle BML Codelab环境使用说明 - 知识点目录
《Paddle BML Codelab环境使用说明》 1. 编辑区 Code Cell 1.1 Code Cell 操作 Magic关键字/魔术命令 Magic命令含义%timeit测试单行语句的执行时间%%timeit测试代码块的执行时间%matplotlib inline显示matplotlib生成的图形%run调用外部python脚本%pdb 调试程序%pwd 查看当…...
python正则表达式处理文本-re模块
python正则表达式处理文本-re模块 1.概述 正则表达式通常用于含有大量文本处理的应用当中。例如,它们经常用作开发者使用的文本编辑程序的搜索模式,包括 vi,emacs 和现代集成开发环境。它们也是 Unix 命令行工具的组成部分,例如…...
换了固态硬盘需要重装系统吗?教你如何实现不重装系统!
电脑大家都用过嘛,如果您的计算机装的还是机械硬盘,想必阁下肯定是修身养性的高手,因为在这个浮躁的社会中,是很少有人能够忍受5分钟甚至更久的开机时间的,不仅开机慢,应用程序的响应速度也很慢,…...
网上医疗预约挂号系统
技术:Java、JSP等摘要:网上医疗预约挂号系统是主要是对居民的保健、护理、疾病预防等健康信息实行有效的预约挂号管理。医疗机构为居民建立完整的健康档案,安排体检以及实施免疫等预防措施。而基于Web的远程保健平台以网上医疗预约挂号系统为…...
专题:一看就会的C++类模板讲解 (1)
目录 一.类模板的作用 二.类模板的定义: 三.类模板的声明格式: 四.类模板对象 五.再举一个例子 一.类模板的作用 面向对象的程序设计编程实践中,我们可能会面临这样的问题:要实现比较两个数的大小。明明比较两个数的方法都一样…...
什么是“奥卡姆剃刀”,如何用“奥卡姆剃刀”解决复杂问题?复杂问题简单化
什么是“奥卡姆剃刀”,如何用“奥卡姆剃刀”解决复杂问题?复杂问题简单化问题什么是“奥卡姆剃刀”?如何使用“奥卡姆剃刀”解决问题复杂问题简单化“汉隆剃刀”小结问题 假设你在夜空中看到一颗闪闪发光的「不明飞行物」,你认为这会是什么呢…...
角谷定理(递归)
已知有角谷定理: 输入一个自然数,若为偶数,则把它除以2,若为奇数,则把它乘以3加1。经过如此有限次运算后,总可以得到自然数值1。求经过多少次可得到自然数1。如:例如数据22的变化过程ÿ…...
数学小课堂:微积分复盘(高等数学本质上是对趋势的动态描述,是对各种相关性抽象的表述。)
文章目录 引言I 复盘1.1 概念和表述1.2 现实与虚构1.3 有穷和无穷1.4 静态和动态1.5 直觉和逻辑II 通过数学逻辑,理解人生。2.1 精明与聪明2.2 朋友和理性的对手2.3 攒钱和赚钱2.4 荣誉和财富引言 高等数学本质上是对趋势的动态描述,是对各种相关性抽象的表述。 I 复盘 1.…...
JAVA线程池原理详解一
JAVA线程池原理详解一 一. 线程池的优点 线程是稀缺资源,使用线程池可以减少创建和销毁线程的次数,每个工作线程都可以重复使用。可以根据系统的承受能力,调整线程池中工作线程的数量,防止因为消耗过多内存导致服务器崩溃。 二…...
Windows平台Unity Camera场景实现轻量级RTSP服务和RTMP推送
技术背景随着VR技术在医疗、军事、农业、学校、景区、消防、公共安全、研学机构、展厅展馆,商场等场所普及,开发者对Unity平台下的直播体验提出了更高的要求。技术实现Unity平台下的RTMP推流、RTMP、RTSP播放前几年已经覆盖了Windows、Linux、Android、i…...
LSB 题解
今天来刷一道Misc的题目,LSB原理进行图片隐写 LSB原理 LSB是一种利用人类视觉的局限性设计的幻术 PNG和BMP图片中的图像像素一般是由RGB(RED红 GREEN绿 BLUE蓝)三原色组成 记住,JPG图片是不适合使用LSB隐写的,JPG图片对像数进行了有损压缩…...
离线部署docker与镜像
离线部署docker与镜像 1.离线部署docker 1).在docker官网上下载,合适的安装文件 本次使用的是“docker-20.10.9.tgz ” 下载地址:https://download.docker.com/linux/static/stable/x86_64/ [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下…...
Linux文件系统介绍(上)
使用 Linux 系统时,需要作出的决策之一就是为存储设备选用什么文件系统。大多数 Linux 发行版在安装时会非常贴心地提供默认的文件系统,大多数入门级用户想都不想就用了默认的那个。 使用默认文件系统未必就不好,但了解一下可用的选择有时也会…...
创建SpringBoot注意事项
作为一个java小白,你是否因为创建SpringBoot项目那些莫名其妙的错误搞得头皮发麻。不要慌张,这篇文章能帮你解决90%的问题【持续更新…】 本文结合创建SpringBoot项目的完整过程来讲 在idea中新建项目 虽然SpringBoot项目是由maven内核组成的࿰…...
2023年全国最新二级建造师精选真题及答案9
百分百题库提供二级建造师考试试题、二建考试预测题、二级建造师考试真题、二建证考试题库等,提供在线做题刷题,在线模拟考试,助你考试轻松过关。 11.关于施工合同违约赔偿损失范围的说法,正确的是()。 A.…...
南京做网站建设的公司/深圳网络推广推荐
虚拟环境 virtualenv官网 虚拟环境其实就是对真实pyhton环境的复制,这样我们在复制的python环境中安装包就不会影响到真实的python环境。通过建立多个虚拟环境,在不同的虚拟环境中开发项目就实现了项目之间的隔离。 安装 1.安装virtualenv sudo pip…...
清河网站建设设计费用/泉州关键词排名工具
MySQL 5.5 版本,编译安装使用 cmake 。cmake 安装之前,如果已经运行过 cmake,尝试运行下面的命令来避免冲突,# make clean# find / -iname "cmakecache.txt" | rm 编译安装的时候,需要指定 DDEFAULT_CHARET…...
网络搭建与维护/性价比高seo排名优化的
一、背景: 小编在爬虫的时候肯定会遇到被封杀的情况,昨天爬了一个网站,刚开始是可以了,在settings的设置DEFAULT_REQUEST_HEADERS伪装自己是chrome浏览器,刚开始是可以的,紧接着就被对方服务器封杀了。 代理…...
网站建设公司年终总结/代写文章平台
文章目录死锁线程间的同步条件变量生产者与消费者模型生产者与消费者模型代码实现信号量死锁 死锁描述的是程序流程无法继续推进的情况——多个线程对锁资源进行争抢获取,但是因为流程推进顺序不当造成互相等待,最终流程无法推进(程序流程因…...
自适应全屏网站/网站关键词优化建议
今年比往年要特殊一些,受疫情的影响,很多公司都出现了裁员现象。以至于最近很多技术同学也在纷纷向我倒苦水。 王鹏便是其中的一员,王鹏之前是在一线城市的一家小型互联网公司做测试开发。从毕业实习到今年,工作整整六年。六年之…...
小白怎样建设公司网站/网站的推广
我们几乎每天都会用微信,微信里的收藏功能其实非常强大,今天教授就来分享一下,微信的收藏功隐藏的6个玩法。拼长图平时聊天、工作免不了要分享一些有趣好笑或者很有用的图片给好友、同事,不过要是信息量太多,就需要一张…...