1.RTOS的实时性是如何保证的
通过多种技术和算法来保证
1.抢占式调度:RTOS使用抢占式调度算法来确保高优先级任务可以在低优先级任务之前执行。
2.中断处理:RTOS使用中断处理技术来响应外部事件,中断处理程序通常是高优先级任务。
3.时间片轮转:RTOS使用时间片轮转算法来确保每个任务都有机会执行。每个任务被分配一个时间片,当时间片用完,RTOS会中断当前任务并切换到下一个任务。
4.优先级反转:RTOS使用优先级反转技术来解决优先级翻转问题。当一个低优先级任务占用了一个共享资源,而一个高优先级任务需要访问该资源时,RTOS会将低优先级任务的优先级提升到高优先级的优先级,以确保高优先级任务可以及时访问共享资源。
2.任务之间是怎么通信的
1.共享内存。速度快,缺点时需要处理同步和互斥问题,否则可能出现数据不一致的情况。
2.消息队列。可以实现异步通信,简单易用,缺点需要额外的内存开销。
3.信号量。进行同步和互斥,可以用来保护共享资源,缺点是需要处理死锁和优先级反转问题。
4.管道。无名管道只能在具有亲缘关系的进程之间使用。
3.二值信号量和互斥量的区别
二值信号量和互斥量都可以用来保护共享资源。通常情况下,二值信号量用于保护二进制资源,例如硬件寄存器或者文件系统。而互斥量用于保护复杂资源,例如数据结构或者网络连接。
互斥型信号量必须是同一个任务申请,同一个任务释放,其他任务释放无效。同一个任务可以递归申请。
二进制信号量,一个任务申请成功后,可以由另一个任务释放
4.任务通知是怎么实现的
任务通知可以使用同步机制,例如二进制信号量或互斥锁来保护表示任务的共享资源。当创建任务时,它可以获取同步对象并等待来自另一个任务或系统的通知。当任务被通知时,它可以释放同步对象并继续执行
5.TCP的三次握手
客户端发送SYN, 服务器端接收消息后返回SYN和ACK,客户端接收到消息,返回ACK
6.TCP的四次挥手
客户端发送FIN,服务器接收到消息,返回ACK,然后服务器再发送FIN,客户端接收到消息后,返回ACK
7.TCP和UDP的区别
TCP是面向连接的协议,提供可靠的数据传输和错误检测,但是会增加一定的开销。UDP是无连接的协议,是不可靠的,但具有较低的开销。
8.什么情况下使用UDP
UDP协议适用于实时应用程序,如音频和视频流,以及快速传输数据而不需要可靠性的应用程序。
9.反转字符串
void reverse_string(char *str)
{
int len = strlen(str);
for (int i = 0; i < len / 2; i++) {
char temp = str[i];
str[i] = str[len - i - 1];
str[len - i - 1] = temp;
}
}
10.判断链表是否有环
typedef struct ListNode {
int val;
struct ListNode *next;
}ListNode;
bool hasCycle(ListNode *head) {
if (head == NULL || head->next == NULL) {
return false;
}
ListNode *slow = head;
ListNode *fast = head->next;
while (slow != fast) {
if (fast == NULL || fast->next == NULL) {
return false;
}
slow = slow->next;
fast = fast->next->next;
}
return true;
}
11.数字字符转换成IP地址
/* 待转化的整数IP */
unsigned int IP_Addr = 1713350848;
/* 提取IP:位移操作 */
int addr_1 = IP_Addr >> 24; // 提取第一部分IP地址
IP_Addr = IP_Addr << 8;
int addr_2 = IP_Addr >> 24; // 提取第二部分IP地址
IP_Addr = IP_Addr << 8;
int addr_3 = IP_Addr >> 24; // 提取第三部分IP地址
IP_Addr = IP_Addr << 8;
int addr_4 = IP_Addr >> 24; // 提取第四部分IP地址
/* 提取IP:求余取整 */
int addr_1 = IP_Addr % 256; // 提取第一部分IP地址
IP_Addr = IP_Addr / 256;
int addr_2 = IP_Addr % 256; // 提取第一部分IP地址
IP_Addr = IP_Addr / 256;
int addr_3 = IP_Addr % 256; // 提取第一部分IP地址
IP_Addr = IP_Addr / 256;
int addr_4 = IP_Addr % 256; // 提取第一部分IP地址
/* 打印IP地址:结果为"192.168.31.102" */
printf("IP地址为:%d.%d.%d.%d", addr_4, addr_3, addr_2, addr_1);
/********************** 字符串IP转整数就比较简单了 ***************************/
/* 待转换字符串IP */
char * IP_Addr = "192.168.31.102";
/* 提取4部分整数:提取方法很多这里省略 */
int addr_1 = 192;
int addr_2 = 168;
int addr_3 = 31;
int addr_4 = 102;
/* 根据网络字节倒序计算IP整数 */
unsigned int IP_Int = addr_1 + (addr_2 * 256) + (addr_3 * 256 * 256) + (addr_4 * 256 * 256 *256);
#include <stdio.h>
int main()
{
char ip[32] = "192.168.1.151"; //IP值
char scIPAddress[32] = ""; //存储字符串IP
unsigned int nIPAddress = 0; //存储整形IP
int nTmpIP[4] = {0}; //分割IP
int i=0;
//字符串转整形
sscanf(ip,"%d.%d.%d.%d",&nTmpIP[0],&nTmpIP[1],&nTmpIP[2],&nTmpIP[3]);
for(i=0;i<4;i++)
{
nIPAddress += (nTmpIP[i]<<(24-(i*8)) & 0xFFFFFFFF);
}
//输出
printf("整形IP:%u\r\n",nIPAddress);
//整形转字符串
sprintf(scIPAddress,"%d.%d.%d.%d", nIPAddress>> 24, (nIPAddress & 0xFF0000) >> 16, (nIPAddress & 0xFF00) >> 8, nIPAddress & 0xFF);
//输出
printf("字符串IP:%s\r\n",scIPAddress);
return 0;
}
12.简单说一下内核是怎么调度
内核调度器在操作系统中负责决定哪些进程可以使用CPU以及使用多长时间。调度器使用各种算法来做出这些决策,例如轮转调度、优先级调度和多级反馈队列调度。
13.判断一个数是不是回文数
bool is_palindrome(int num) {
char num_str[20];
sprintf(num_str, "%d", num);
int len = strlen(num_str);
for (int i = 0; i < len / 2; i++) {
if (num_str[i] != num_str[len - i - 1]) {
return false;
}
}
return true;
}
14.堆和栈的区别
栈是一种后进先出的数据结构用于存储函数调用和局部变量等信息。堆是一种动态分配内存的方式,用于存储动态分配的对象,例如数组和结构体等。
栈是由编译器自动分配和管理的,而堆是由程序员手动分配和管理的。栈的大小是固定的,通常在程序编译时已经确定了,堆的大小是动态的,可以在程序运行时根据需要进行调整。