memcpy和strcpy的区别?

1)、复制的内容不同。strcpy只能复制字符串,而memcpy可以复制任意内容,例如字符数组、整型、结构体、类等。

2)、复制的方法不同。strcpy不需要指定长度,它遇到被复制字符的串结束符”\0”才结束,所以容易溢出。memcpy则是根据其第3个参数决定复制的长度。

3)、用途不同。通常在复制字符串时用strcpy,而需要复制其他类型数据时则一般用memcpy

信号量与互斥锁的区别?

(1)、互斥锁用于线程的互斥,信号量用于线程的同步。

互斥:是指某一资源同时只允许一个访问者对其进行访问,具有唯一性和排它性。但互斥无法限制访问者对资源的访问顺序,即访问是无序的。

同步:是指在互斥的基础上(大多数情况),通过其它机制实现访问者对资源的有序访问。在大多数情况下,同步已经实现了互斥,特别是所有写入资源的情况必定是互斥的。少数情况是指可以允许多个访问者同时访问资源。

(2)、互斥量值只能为0/1,信号量值可以为非负整数。

也就是说,一个互斥量只能用于一个资源的互斥访问,它不能实现多个资源的多线程互斥问题。信号量可以实现多个同类资源的多线程互斥和同步。当信号量为单值信号量是,也可以完成一个资源的互斥访问。

(3)、互斥量的加锁和解锁必须由同一线程分别对应使用,信号量可以由一个线程释放,另一个线程得到。

简述程序编译过程?

预处理:预处理相当于根据预处理命令组装成新的C程序,不过常以i为扩展名。

编译: 将得到的i文件翻译成汇编代码.s文件。

汇编:将汇编文件翻译成机器指令,并打包成可重定位目标程序的O文件。该文件是二进制文件。

链接:将引用的其他O文件并入到我们程序所在的o文件中,处理得到最终的可执行文件。

TCP服务器搭建流程?

Socket套接字就是网络上进程通信的一端,提供了应用层进程利用网络协议交换数据的机制。

  • 1、创建套接字socket ()
  • 2、保存服务器信息
  • 3、套接字绑定
  • 4、 监听客户端连接请求
  • 5、 接收客户端连接请求
  • 6、数据收发
  • 7、关闭套接字

socket三次握手四次挥手

什么是进程线程?

进程(Process) 是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,

线程(thread) 是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。

父进程与子进程的关系和区别?

fork出子进程后,子进程都会继承父进程以下信息:

  • 文件描述符
  • 实际用户ID,实际组ID,有效用户ID,有效组ID
  • 进程组ID
  • 添加组ID
  • 对话期ID
  • 控制终端
  • 设置-用户-ID标志和设置-组-ID标志
  • 当前工作目录
  • 根目录
  • 文件方式创建字
  • 信号屏蔽和排列
  • 对任意打开文件描述符大的在执行时关闭标志
  • 环境
  • 接的共享存储段
  • 资源限制

区别

  • fork的返回值
  • 进程ID
  • 不同的父进程ID
  • 子进程的tms_utime、tms_stime、tms_sutime、tms_ustime设置为0
  • 父进程设置的锁,子进程不继承
  • 子进程的未决告警被清除
  • 子进程的未决信号集设置为空集

多进程、多线程同步(通讯)的方法?

管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。
有名管道 (namedpipe) : 有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。
高级管道(popen):将另一个程序当做一个新的进程在当前程序进程中启动,则它算是当前程序的子进程,这种方式我们成为高级管道方式。
信号量( semophore ) :信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
消息队列( messagequeue ) : 消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
信号 ( sinal ) :信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。
共享内存( sharedmemory ) :共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号两,配合使用,来实现进程间的同步和通信。
套接字( socket ) : 套解口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同及其间的进程通信。

什么是线程同步和互斥

线程同步:每个线程之间按预定的先后次序进行运行,协同、协助、互相配合。可以理解成“你说完,我再做”。有了线程同步,每个线程才不是自己做自己的事情,而是协同完成某件大事。

线程互斥:当有若干个线程访问同一块资源时,规定同一时间只有一个线程可以得到访问权,其它线程需要等占用资源者释放该资源才可以申请访问。线程互斥可以看成是一种特殊的线程同步

线程同步与阻塞的关系?同步一定阻塞吗?阻塞一定同步吗?

同步是个过程,阻塞是线程的一种状态。多个线程操作共享变量时可能会出现竞争。这时需要同步来防止两个以上的线程同时进入临界区,在这个过程中,后进入临界区的线程将阻塞,等待先进入的线程走出临界区。
线程同步不一定发生阻塞,线程同步的时候,需要协调推进速度,互相等待和互相唤醒会发生阻塞。

并发,同步,异步,互斥,阻塞,非阻塞的理解

并发(concurrency):在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行。其中两种并发关系分别是同步和互斥。
1.互斥:是指某一资源同时只允许一个访问者对其进行访问,具有唯一性和排它性。但互斥无法限制访问者对资源的访问顺序,即访问是无序的。  
2.同步:是指在互斥的基础上(大多数情况),通过其它机制实现访问者对资源的
有序访问
。在大多数情况下,同步已经实现了互斥,特别是所有写入资源的情况必定是互斥的。少数情况是指可以允许多个访问者同时访问资源。
**异步(asynchronous)**:异步和同步是相对的,同步就是顺序执行,执行完一个再执行下一个,需要等待、协调运行。异步就是彼此独立,在等待某事件的过程中继续做自己的事,不需要等待这一事件完成后再工作。线程就是实现异步的一个方式。异步是让调用方法的主线程不需要同步等待另一线程的完成,从而可以让主线程干其它的事情。

阻塞非阻塞是针对于进程在访问数据的时候,根据IO操作的就绪状态来采取的不同方式,说白了是一种读取或者写入操作函数的实现方式。阻塞方式下读取或者写入函数将一直等待,而非阻塞方式下,读取或者写入函数会立即返回一个状态值。
一般来说IO模型可以分为:同步阻塞,同步非阻塞,异步阻塞,异步非阻塞。
同步阻塞IO :用户进程在发起一个IO操作以后,必须等待IO操作的完成,只有当真正完成了IO操作以后,用户进程才能运行。
同步非阻塞IO :用户进程发起一个IO操作以后可返回做其它事情, 但是用户进程需要时不时的询问 IO操作是否就绪,这就要求用户进程不停的去询问,从而引入不必要的CPU资源浪费。应用发起一个IO操作以后,使用阻塞select系统调用 来等待 I/O可用的通知。 select 调用非常有趣的是它可以用来为多个IO描述符提供通知,而不仅仅为一个描述符提供通知。
异步阻塞IO :应用发起一个IO操作以后,不等待内核IO操作的完成, 等内核完成IO操作以后会通知应用程序,这其实就是同步和异步最关键的区别同步必须等待或者主动的去询问IO是否完成。

孤儿进程、僵尸进程、守护进程的概念

一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程所收养,并由init进程对它们完成状态收集工作。
一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵死进程

正确处理僵尸进程的方法

1.子进程退出时向父进程发送SIGCHILD信号,父进程处理SIGCHILD信号。在信号处理函数中调用wait进行处理僵尸进程。
2.把父进程杀掉。父进程死后,僵尸进程成为”孤儿进程”,过继给进程init,init始终会负责清理僵尸进程。它产生的所有僵尸进程也跟着消失。
fork两次,父进程fork一个子进程,然后继续工作,子进程fork一 个孙进程后退出,那么孙进程被init接管,孙进程结束后,init会回收。不过子进程的回收 还要自己做。
两次fork的原理是将子进程成为孤儿进程,从而其的父进程变为init进程,通过init进程可以处理僵尸进程

系统调用作用?

(1) 系统调用可以为用户空间提供访问硬件资源的统一接口,以至于应用程序不必去关 注具体的硬件访问操作。
(2) 系统调用可以对系统进行保护,保证系统的稳定和安全。系统调用的存在规定了用 户进程进入内核的具体方式,

用户态和内核态的区别

内核态和用户态是操作系统中的两种运行模式。 内核态是操作系统运行在特权级别最高的模式下,具有访问系统资源和执行特权指令的能力。 在内核态下,操作系统拥有完全的控制权,可以直接访问硬件设备和系统资源。 操作系统的内核代码运行在内核态下,可以执行诸如管理进程、内存管理、文件系统等核心功能的操作。 用户态是应用程序运行在较低特权级别下的模式。

Linux内核同步方式总结

1.per-cpu 变量:将内核变量声明为per-cpu变量,它的数据结构是数组,系统的每个CPU对应数组中的一个元素,一个CPU只能修改自己对应的元素,不用担心竞争条件。per-cpu只能对来自不同CPU的并发访问提供保护,但对自身的异步函数(中断处理函数和可延迟函数)的访问不提供保护,需要同步原语

2.原子操作(linux中有一个专门的atomic_t类型):操作在芯片级是原子的,原子操作必须以单个指令执行,中间不能中断,且避免其他的CPU访问同一存储器单元。

**3.优化屏障(optimization barrier)和内存屏障(memory barrier)**:现代编译器可能重新安排汇编语言指令的吮吸,CPU通常并行的执行多条指令,且可能重新安排内存访问,但是,当处理同步时,必须避免指令重新排序,如果放在同步原语之后的一条指令在同步原语之前被执行,就很糟糕!内存屏障:确保在原语之后的操作开始执行之前,原语之前的操作已经完成。mb(), smp_mb();

4.spin lock:当内核控制路径必须访问共享数据结构或进入临界区时,需要锁,spin lock的循环指令表示“忙等”,即使等待的内核控制路径无事可做,它也在CPU上保持运行

5.读写spin lock:它的引入主要是为了增加内核的并发能力,只要没有内核路径对数据结构进行修改,读写spin lock允许多个内核控制路径同时读同一个数据结构。但是写者需要独占。

6.顺序锁:读写spin lock中读者和写着有相同的优先级,当读者多的时候,可能出现一种情况,写着一直得不到服务,可能饥饿。引入顺序锁(seqlock),它与读写spin lock非常相似,但是它赋予写着较高的优先级。

7.RCU(read-copy update):是为了保护在多数情况下被多个CPU读的数据结构而设计的另一种同步方式。RCU允许多个读者和写者并发执行,而且RCU不使用锁。

为什么需要BootLoader?

BootLoader就是在操作系统运行之前运行的一段小程序。通过这段小程序,可以初始化硬件设备,从而将系统的软硬件环境带到一个合适的状态,以便为最终调用操作系统做好准备。

为什么自旋锁不能睡眠 而在拥有信号量时就可以?

自旋锁自旋锁禁止处理器抢占;而信号量不禁止处理器抢占。

  基于这个原因,如果自旋锁在锁住以后进入睡眠,由于不能进行处理器抢占,其他系统进程将都不能获得CPU而运行,因此不能唤醒睡眠的自旋锁,因此系统将不响应任何操作(除了中断或多核的情况,下面会讨论)。而信号量在临界区睡眠后,其他进程可以用抢占的方式继续运行,从而可以实现内存拷贝等功能而使得睡眠的信号量程序由于获得了等待的资源而被唤醒,从而恢复了正常的代码运行。

linux下检查内存状态的命令

top、 free、 cat /proc/meminfo

产生死锁的四个必要条件

① 互斥条件——进程要求对所分配的资源进行排它性控制,即在一段时间内某资源仅为一进程所占有。
② 请求和保持条件——当进程因请求资源而阻塞时,对已获得的资源保持不放。
③ 不剥夺条件——进程已获得的资源,在未使用完之前,不能被剥夺,只能在使用完时由自己释放。
④ 环路等待条件——在发生死锁时必然存在一个“进程—资源”的环形链。

解决死锁的基本方法(四种)

① 预防死锁——通过设置某些限制条件,以 破坏产生死锁的四个必要条件中的一个或几个 ,来防止发生死锁。
② 避免死锁——在资源的动态分配过程中,使用某种方法去 防止系统进入不安全状态 ,从而避免了死锁的发生。

硬链接和软连接

软连接可以是任意文件或目录,可以链接不同文件系统的文件,在对符号文件进行读或写操作的时候,系统会自动把该操作转换为对源文件的操作,但删除链接文件时,系统仅仅删除链接文件,而不删除源文件本身,这一点类似于 Windows 操作系统下的快捷方式

在 Linux 中,多个文件名指向同一索引节点是存在的,所以硬连接指通过索引节点来进行的连接,即每一个硬链接都是一个指向对应区域的文件。

说明总线接口USART、I2C、USB的异同点(串/并、速度、全/半双工、总线拓扑等)

UART:通用异步串行口,速率不快,可全双工,结构上一般由波特率产生器、UART发送器、UART接收器组成,硬件上两线,一收一发。

I2C:双向、两线、串行、多主控接口标准。速率不快,半双工,同步接口,具有总线仲裁机制,非常适合器件间近距离经常性数据通信,可实现设备组网。

SPI:高速同步串行口,高速,可全双工,收发独立,同步接口,可实现多个SPI设备互联,硬件3~4线。

USB:通用串行总线,高速,半双工,由主机、hub、设备组成。设备可以与下级hub相连构成星型结构

写出计算机网络五层模型,每一层对应的协议

计算机网络五层模型如下:
物理层:负责物理传输介质上的比特流传输,例如光纤、网线等。常用协议有:RS-232、V.35、10Base-T等。
数据链路层:负责将比特流划分为数据帧并进行差错检测和纠正,同时也进行物理寻址和流量控制。常用协议有:以太网、令牌环、HDLC、PPP等。
网络层:负责数据的路由选择和分组转发,将数据包发送到目标地址。常用协议有:IP、ICMP、ARP、RIP、OSPF、BGP等。
传输层:提供可靠的端到端的数据传输,负责数据的分段、排序、传输错误恢复等。常用协议有:TCP、UDP等。
应用层:为用户提供各种网络应用服务,如电子邮件、文件传输、远程登录、Web服务等。常用协议有:HTTP、SMTP、POP3、FTP、Telnet等。

C/C++程序 内存分布情况 常量所在的区

C/C++程序内存分布情况通常可以分为以下几个区域: 代码区(text segment):存放程序执行代码的区域,通常是只读的。该区域的内容在程序执行时不能被修改。 数据区(data segment):存放已经初始化的全局变量和静态变量(包括全局和静态变量的指针)的区域。 BSS区(bss segment):存放未初始化的全局变量和静态变量的区域,该区域的值默认初始化为0。 栈区(stack segment):存放函数调用时的局部变量、函数参数和返回地址等信息。栈空间是由操作系统自动分配和回收的,它的大小通常是固定的,不能随意增加。栈空间是向下增长的,也就是说,栈顶的地址是越来越小的。 堆区(heap segment):存放由程序员手动申请的内存空间,大小可以动态增加或减少。堆空间是由程序员手动管理的,程序员需要负责在使用完毕后将其释放。堆空间是向上增长的,也就是说,堆顶的地址是越来越大的。

linux7种文件设备类型

Linux中文件设备类型有7种,分别是:块设备(block)、字符设备(character)、套接字(socket)、符号链接(symbolic link)、FIFO、目录(directory)和文件(regular file)。

Linux开发板写一个SPI的驱动

注册SPI驱动

  • 使用spi_register_driver函数注册SPI驱动,指定驱动的probe和remove函数。

probe函数

  • 当系统检测到SPI设备时,会调用probe函数。
  • 在probe函数中,通常需要完成以下操作:
    • 获取SPI设备的相关信息(如速率、模式、片选号等)。
    • 分配和初始化资源,如内存空间、中断处理等。
    • 注册SPI设备,使用spi_new_device函数。

remove函数

  • 当SPI设备被卸载时,会调用remove函数。
  • 在remove函数中,需要完成资源的释放和清理工作,如注销SPI设备等。

SPI传输函数

  • 使用spi_syncspi_async等函数进行数据传输。
  • spi_sync函数用于同步传输数据,适合简单的数据交换。
  • spi_async函数用于异步传输数据,支持更复杂的数据处理需求。

linux开发板写一个IIC的驱动

驱动框架过程:

  1. 注册IIC驱动
    • 使用i2c_register_driver函数注册IIC驱动,指定驱动的probe和remove函数。
  2. probe函数
    • 当系统检测到IIC设备时,会调用probe函数。
    • 在probe函数中,通常需要完成以下操作:
      • 获取IIC设备的相关信息(如地址、速率等)。
      • 分配和初始化资源,如内存空间、中断处理等。
      • 注册IIC设备,使用i2c_new_device函数。
  3. remove函数
    • 当IIC设备被卸载时,会调用remove函数。
    • 在remove函数中,需要完成资源的释放和清理工作,如注销IIC设备等。
  4. IIC传输函数
    • 使用i2c_transfer函数进行数据传输。
    • i2c_transfer函数支持主从模式的数据交换,适用于IIC总线上的读写操作。

Linux开发板写一个LED显示的驱动

驱动框架过程:

  1. LED设备结构
    • 定义LED设备的数据结构,包括LED状态、控制方式等信息。
  2. 设备树配置
    • 在设备树中描述LED设备的连接信息,如GPIO引脚、控制器等。
  3. probe函数
    • 当系统检测到LED设备时,会调用probe函数。
    • 在probe函数中,通常需要完成以下操作:
      • 初始化LED设备,包括配置GPIO引脚或控制器。
      • 注册LED设备,使其可被系统管理。
  4. remove函数
    • 当LED设备被卸载时,会调用remove函数。
    • 在remove函数中,需要完成资源的释放和清理工作,如关闭GPIO引脚等。

生成的可执行文件,其中每个段存在的位置在ROM还是RAM

  1. 当系统上电后根据BOOT的引导配置选择启动方式,默认是Flash启动,这时系统开始把所有的代码段搬到RAM中去运行
  2. CPU就从内存中(RAM)获取数据和指令,根据相关指令来控制系统运行
  3. 数据存放位置:除了特定IO操作存到EEPROM里面,其他变量的使用全在RAM区,其中就有堆和栈。是由用户手动分配malloc,在整个程序运行期间都有效除非手动释放free。而在一个函数体内存在,例如main方法由系统自动创建,如果出现递归创建则很容易导致栈溢出,当系统执行完该函数功能后,栈空间数据也由系统自动销毁。