44、深入探讨Xenomai与RT补丁:实现Linux实时性的关键技术

深入探讨Xenomai与RT补丁:实现Linux实时性的关键技术

一、Xenomai的POSIX接口与代码示例

在实时系统开发中,Xenomai提供了与标准Linux编程模型相近的POSIX接口。以下是一段代码示例:

fd = open("/dev/rtdev", O_RDWR);
if (fd < 0)
    error(1, errno, "open failed");
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
pthread_attr_setschedparam(&attr, &param);
pthread_create(&tid, &attr, &test_thread, NULL);
pthread_join(&tid, NULL);
return 0;

这段代码展示了如何使用Xenomai的POSIX接口进行设备打开和线程创建。其中, open() pthread_create() pthread_join() 等函数使用了Xenomai的实现,以确保短且可预测的响应时间。而其他POSIX服务仍从标准的glibc获取。这意味着在一个应用程序中,可以混合使用Xenomai的POSIX实现和标准RTOS的POSIX实现。不过,只有Xenomai提供的函数能保证实时行为。当打开非RTDM设备时,Xenomai接口库会自动将请求转发给标准glibc。

二、Xenomai的双内核架构

Xenomai目前采用基于Adeos/I - pipe虚拟化层的双内核架构,这种架构具有以下优点:
1. 解耦开发周期 :将Xenomai与主线Linux的开发周期解耦,开发者在选择内核基础时更自由,同时减少标准内核潜在回归故障对实时子系统的影响。
2. 保护应用程序 :在实时模式下,Xenomai应用程序不受常规不良应用程序的影响,因为它们由不同的内核控制。
3. 便于问题追踪 :开发者可以在协内核域中查找实时问题(如意外延迟)的原因,相比常规内核,需要审计的代码量少很多。
4. 轻量级设计 :协内核依赖主机内核提供非时间关键服务,因此实现实时保证的成本仅由需要的应用程序承担,Linux主机内核除了虚拟化中断掩码(这是一个低成本操作)外,无需处理实时问题。

然而,这种设计也有缺点。它将依赖标准内核的常规Linux驱动和库排除在实时域之外,在一些应用场景中,这可能是一个重大缺陷,尤其是当实现中混合了非实时和时间关键活动时,或者使用具有有界响应时间的常规驱动能以更低的工程成本满足系统需求时。

三、Xenomai与PREEMPT_RT的结合

Xenomai的目标是帮助传统RTOS应用程序更轻松地迁移到Linux。而PREEMPT_RT为在单内核系统中实现短且有界的延迟开辟了一条有前景的道路。截至Linux内核2.6.24,Xenomai模拟器正在向支持PREEMPT_RT的内核移植,这个项目代号为Xenomai/SOLO。它由开源自动化开发实验室、DENX软件工程公司和Xenomai项目共同赞助。这种纯原生实现与现有的RTDM层原生版本相结合,将使传统实时应用程序更容易移植到Linux,同时为选择支持它们的底层内核技术提供更多选择,并利用不断增长的工业设备驱动基础。

四、Linux内核实时化的努力

过去几年,Linux社区一直在努力将Linux内核转变为真正的实时操作系统(RTOS),而无需微内核的帮助。为了实现这一目标,需要对内核进行一些更改。例如,中断服务例程不能无条件地抢占CPU上运行的任何进程,关键部分的保护范围需要缩小,以仅阻止可能访问它们的进程,并且不允许无界优先级反转。

早期,有公司尝试实现完整的实时Linux内核,如TimeSys在Linux 2.2和2.4版本时,从主线内核分支创建并支持自己的内核,但维护一个独立于主线Linux树的内核非常困难。后来,Ingo Molnar发起了针对主线内核的RT补丁,他的观点与其他实时开发者不同,他从长期Linux内核开发者的角度为系统添加实时特性,以改善用户体验。许多在RT补丁中开发的特性已经融入主线内核,如高分辨率定时器、内核锁验证、通用中断、健壮的futexes甚至优先级继承等。

五、Linux内核的中断处理机制

当前的Linux内核(如2.6.22版本)有多种处理设备工作的方法。当设备执行需要CPU操作的异步事件且中断启用时,设备会发送中断信号,CPU会暂停当前工作,执行该设备的中断服务例程(ISR)。ISR的执行优先级高于任何用户任务,并且在执行时会禁用CPU上的中断或至少屏蔽当前中断线。只有另一个中断才能抢占ISR,前提是ISR允许重新启用中断。

一个编写良好的设备驱动会尽量减少ISR中的工作量,将其他工作推给内核线程、小任务(tasklet)或软中断(softirq)。以下是它们的特点:
- 软中断(softirq) :在ISR返回后、被中断的进程恢复之前执行。如果有太多软中断排队,内核会唤醒一个高优先级的内核线程(ksoftirqd)来完成它们。关于“太多软中断”的定义在核开发中存在争议。当软中断在中断禁用的情况下启动,或者软中断例程在返回被抢占的进程之前被处理多次时,ksoftirqd线程就会启动。
- 小任务(tasklet) :与软中断类似,也在ISR之后、被中断的进程恢复之前执行。不同的是,同一个软中断可以在两个不同的CPU上同时运行,而小任务不能。因此,软中断需要使用锁来保护非本地数据或其他资源,而小任务不需要,即小任务不需要是可重入的。此外,小任务函数可以在触发它的CPU之外的其他CPU上运行,小任务实际上是由软中断实现的,实现小任务的软中断函数会确保两个小任务函数不会同时运行,这也意味着小任务可以由ksoftirqd线程执行。
- 内核线程 :只在内核中运行,可以由ISR唤醒,处理中断服务例程剩余的工作,以便ISR能快速返回,让被抢占的进程或内核活动继续。内核线程的行为与Linux中的其他线程类似,可以被调度、更改优先级、在指定CPU上运行,并由系统管理员像操作其他线程一样进行操作。通常,ISR会使用工作队列,工作队列会将工作排队,由工作内核线程执行。如果内核没有分配特定的工作队列,会使用通用的工作内核线程keventd。由于队列按FIFO顺序处理工作,所以排队到通用keventd线程的任何工作都需要等待前面排队的所有工作函数完成。

内核线程的开销比软中断或小任务略大,但更灵活。在非RT Linux内核中,软中断和小任务不能被任何优先级的进程抢占,相反,它们可以抢占任何进程。因此,尽管内核线程的开销稍大,但它使内核调度器更灵活,给系统管理员更多控制权(不过内核线程可能会忽略信号),这种灵活性在实时环境中尤为重要。

六、RT补丁对中断处理的改进

在传统的Linux系统中,当ISR、软中断或小任务执行时,CPU上运行的任何进程都会被抢占,甚至会抢占为其他设备工作的内核线程。这种行为使得ISR、软中断和小任务成为系统中优先级最高的事件。为了降低这些例程给系统带来的延迟,RT补丁将它们都转换为内核线程。

(一)硬中断请求(IRQ)转换为线程

硬中断请求(IRQ)可以看作是围绕ISR的一个“封装”,从中断抢占CPU到ISR返回CPU恢复正常处理的这段时间。这可能会导致中断反转,即中断服务例程会占用高优先级进程的时间来执行低优先级的工作。

RT补丁通过将中断处理程序转换为线程,将中断反转的时间缩短到最小。当触发中断时,ISR只是唤醒一个内核线程,该线程将运行设备驱动注册的函数,而不是由ISR自己运行中断处理程序。具体流程如下:
1. 当触发中断时,当前在CPU上执行的任何操作仍会被抢占。
2. 在返回之前,只进行中断线的屏蔽和唤醒中断服务线程的操作。
3. 如果中断服务线程的优先级高于当前运行的线程,它将立即被调度并抢占被中断的进程。
4. 如果原线程的优先级高于中断服务线程,处理将继续使用原线程,中断服务线程将在另一个CPU上调度或等待高优先级线程自愿放弃CPU。

不过,仍有一些中断处理程序作为正常的中断服务例程运行,例如定时器中断。RT补丁会尽量使定时器中断尽快返回,以限制它可能导致的延迟。

(二)中断服务线程的管理

为中断服务创建的线程名为IRQ_n,其中n是中断向量的编号。可以使用 ps 命令查看这些线程,例如:

$ ps -e -o pid,rtprio,comm | grep IRQ
   41     50 IRQ-9
  769     50 IRQ-14
  771     50 IRQ-15
  784     50 IRQ-12
  785     50 IRQ-1
 1714     50 IRQ-8
 1722     50 IRQ-20
 1730     50 IRQ-21
 1751     50 IRQ-19
 1762     50 IRQ-22
 1772     50 IRQ-16
 1774     50 IRQ-7
 1839     50 IRQ-17
 1918     50 IRQ-18

还可以通过 cat /proc/interrupts 查看中断信息:

$ cat /proc/interrupts
           CPU0
  0:         91   IO-APIC-edge      timer
  1:      31336   IO-APIC-edge      i8042
  7:          0   IO-APIC-edge      parport0
  8:          0   IO-APIC-edge      rtc
  9:     517591   IO-APIC-fasteoi   acpi
 12:        368   IO-APIC-edge      i8042
 14:     257832   IO-APIC-edge      ide0
 15:     950323   IO-APIC-edge      ide1
 16:          1   IO-APIC-fasteoi   yenta
 17:          1   IO-APIC-fasteoi   yenta
 18:         27   IO-APIC-fasteoi   Intel 82801DB-ICH4 Modem, Intel 82801DB-ICH4 
 19:    1288060   IO-APIC-fasteoi   uhci_hcd:usb3, wifi0
 20:     163173   IO-APIC-fasteoi   uhci_hcd:usb1, eth0
 21:          0   IO-APIC-fasteoi   uhci_hcd:usb2
 22:          2   IO-APIC-fasteoi   ehci_hcd:usb4
NMI:          0
LOC:   32797885
ERR:          0
MIS:          0

所有中断(除了定时器中断)的服务例程都由线程处理。默认情况下,所有IRQ线程的优先级为50,但可以很容易地更改。例如,以root用户身份运行以下命令,将以太网NIC的中断服务线程优先级修改为80:

# chrt -p -f 80 1722
# ps -e -o pid,rtprio,comm | grep IRQ
   41     50 IRQ-9
  769     50 IRQ-14
  771     50 IRQ-15
  784     50 IRQ-12
  785     50 IRQ-1
 1714     50 IRQ-8
 1722     80 IRQ-20
 1730     50 IRQ-21
 1751     50 IRQ-19
 1762     50 IRQ-22
 1772     50 IRQ-16
 1774     50 IRQ-7
 1839     50 IRQ-17
 1918     50 IRQ-18

通过将中断处理为线程,系统管理员可以对中断进行优先级排序,即使硬件不支持优先级中断。

七、线程化中断带来的问题与注意事项

RT补丁允许用户进程的优先级高于中断处理程序。但如果系统管理员对系统缺乏了解,将某些线程设置为高于网络中断线程或软中断线程的优先级,可能会导致系统出现问题。

以下是一个示例代码:

int signal_me;
int do_listen(in_port_t port) {
    int sockfd;
    struct sockaddr_in sin;
    if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) < 0)
        return -1;
    memset(&sin, 0, sizeof(sin));
    sin.sin_family = AF_INET;
    sin.sin_port = htons(port);
    sin.sin_addr.s_addr = htonl(INADDR_ANY);
    if (bind(sockfd, (struct sockaddr*)&sin, sizeof(sin)) < 0)
        goto out_err;
    if (listen(sockfd, 5) < 0)
        goto out_err;
    return sockfd;
 out_err:
    close(sockfd);
    return -1;
}
void *run_listener(void *unused)
{
    int fd;
    fd = do_listen(4321);
    if (fd < 0) {
        perror("bad listen");
        exit(-1);
    }
    while (1) {
        int cfd;
        struct sockaddr_in in;
        socklen_t len;
        cfd = accept(fd, (struct sockaddr*)&in, &len);
        if (cfd < 0) {
            perror("can't accept");
            exit(-1);
        }
        signal_me = cfd + 1;
    }
    close (fd);
    return NULL;
}
void *run_worker(void *unused)
{
    while (1) {
        /*
         * [...]
         *   doing some work
         * [...]
         */
        if (signal_me) {
            signal_me = 0;
            printf("handle the single!\n");
            sleep(100);
        }
    }
    return NULL;
}

在这个例子中,创建了两个线程: run_listener run_worker 。工作线程正在执行一些算法,等待从其他机器接收数据包。当接收到数据包时,监听线程会接受它并通过全局共享变量 signal_me 向工作线程发出信号,让工作线程停止循环并处理数据包。

假设监听线程的优先级高于工作线程,如果系统管理员将这两个线程的优先级设置为高于网络中断线程或软中断线程,那么外部网络数据包将无法到达监听线程,因为网络接口卡的中断线程和网络软中断需要更高的优先级才能将数据包传递给监听线程。

综上所述,Xenomai和RT补丁为Linux系统的实时性提供了重要的支持,但在使用过程中,开发者和系统管理员需要深入理解这些技术的原理和特点,合理配置系统,以确保系统的稳定性和实时性。

深入探讨Xenomai与RT补丁:实现Linux实时性的关键技术

八、RT补丁中中断处理改进的流程图分析

为了更清晰地理解RT补丁对中断处理的改进,我们可以通过流程图来展示其工作流程。以下是使用mermaid语法绘制的流程图:

graph TD;
    A[设备触发中断] --> B[CPU被抢占];
    B --> C[屏蔽中断线];
    C --> D[唤醒中断服务线程];
    D --> E{中断服务线程优先级 > 当前线程优先级};
    E -- 是 --> F[中断服务线程立即调度并抢占原线程];
    E -- 否 --> G[原线程继续执行];
    G --> H{中断服务线程调度到其他CPU或等待};
    H -- 是 --> I[中断服务线程执行];
    F --> I[中断服务线程执行];
    I --> J[中断服务线程完成,恢复原线程或其他调度];

这个流程图展示了RT补丁处理中断的详细过程。当设备触发中断时,CPU首先被抢占,然后进行中断线的屏蔽和中断服务线程的唤醒操作。接着,根据中断服务线程和当前线程的优先级比较结果,决定是立即调度中断服务线程还是让原线程继续执行。最后,中断服务线程完成工作后,系统恢复原线程或进行其他调度操作。

九、Xenomai与RT补丁在不同场景下的应用分析

Xenomai和RT补丁在不同的应用场景中有着各自的优势和适用情况。以下是一些常见场景的分析:

应用场景 Xenomai优势 RT补丁优势
工业自动化 双内核架构提供更好的隔离性,保护实时应用不受常规应用干扰;支持传统RTOS API,便于迁移遗留应用。 将中断处理转换为线程,降低延迟,提高系统实时性;可灵活调整中断优先级,适应不同工业设备需求。
嵌入式系统 轻量级协内核设计,减少资源消耗;与Linux集成度高,可利用丰富的Linux驱动和库。 原生实现,与主线Linux内核兼容性好;一些特性已融入主线内核,便于维护和升级。
网络通信 提供实时的线程创建和管理功能,确保网络数据处理的及时性。 避免中断反转,保证网络数据包的及时接收和处理,提高网络通信的稳定性。

在工业自动化场景中,Xenomai的双内核架构可以有效保护实时应用,防止常规应用的干扰。而RT补丁通过优化中断处理,能够更好地满足工业设备对实时性的严格要求。在嵌入式系统中,Xenomai的轻量级设计和与Linux的高集成度使其成为一个不错的选择,同时RT补丁的原生实现和与主线内核的兼容性也为系统的维护和升级提供了便利。在网络通信方面,两者都能在不同程度上提高网络数据处理的实时性和稳定性。

十、系统管理员配置建议

系统管理员在使用Xenomai和RT补丁时,需要进行合理的配置以确保系统的实时性和稳定性。以下是一些配置建议:

  1. 线程优先级配置

    • 了解系统中各个线程的功能和重要性,根据实际需求设置合理的优先级。例如,对于关键的实时任务,应设置较高的优先级;而对于一些非关键的后台任务,可以设置较低的优先级。
    • 注意避免将用户进程的优先级设置得过高,以免导致中断处理线程无法及时响应,造成系统故障。在设置线程优先级时,要充分考虑中断服务线程和其他线程之间的关系。
  2. 中断服务线程管理

    • 定期检查中断服务线程的运行状态,确保它们能够正常工作。可以使用 ps 命令查看中断服务线程的信息,如优先级、PID等。
    • 根据系统的实际情况,调整中断服务线程的优先级。例如,对于一些对实时性要求较高的设备中断,可以适当提高其服务线程的优先级。
  3. 内核参数调整

    • 熟悉RT补丁和Xenomai相关的内核参数,根据系统需求进行调整。例如,一些参数可以影响中断处理的方式、线程调度的策略等。
    • 在调整内核参数之前,建议先进行测试,观察系统的性能变化,确保调整后的参数不会对系统造成负面影响。
十一、未来发展趋势

随着技术的不断发展,Xenomai和RT补丁也将不断演进,以满足更复杂的实时应用需求。以下是一些未来可能的发展趋势:

  1. 与新兴技术的融合

    • 随着物联网、人工智能等技术的发展,实时系统需要处理更多的数据和复杂的任务。Xenomai和RT补丁可能会与这些新兴技术进行融合,提供更好的支持。例如,在物联网场景中,实时处理传感器数据和控制设备的需求将更加迫切,Xenomai和RT补丁可以通过优化中断处理和线程调度,提高系统的实时性和响应速度。
    • 与容器技术的结合也是一个潜在的发展方向。容器技术可以提供更好的隔离性和资源管理,将Xenomai和RT补丁与容器技术相结合,可以更好地满足多租户环境下的实时应用需求。
  2. 进一步优化性能

    • 继续优化中断处理机制,减少延迟和上下文切换的开销。例如,通过改进线程调度算法、优化中断服务线程的管理等方式,提高系统的实时性能。
    • 提高与硬件的兼容性,更好地支持新型硬件设备。随着硬件技术的不断发展,实时系统需要能够充分利用硬件的特性,Xenomai和RT补丁可以通过优化驱动程序和内核接口,提高与硬件的兼容性和性能。
  3. 社区支持和开源生态建设

    • 加强社区的支持和合作,吸引更多的开发者参与到Xenomai和RT补丁的开发和维护中。社区的力量可以推动技术的不断进步,提供更多的文档、工具和示例代码,方便开发者使用。
    • 完善开源生态建设,促进不同开源项目之间的协作和集成。例如,与其他实时操作系统、开发框架等进行集成,为开发者提供更丰富的选择和更便捷的开发环境。
十二、总结与展望

Xenomai和RT补丁为Linux系统的实时性提供了重要的解决方案。Xenomai的双内核架构和POSIX接口,以及RT补丁对中断处理的改进,都在不同方面提高了Linux系统的实时性能。然而,在使用这些技术时,开发者和系统管理员需要深入理解其原理和特点,合理配置系统,以避免潜在的问题。

未来,随着技术的不断发展和应用场景的不断拓展,Xenomai和RT补丁有望与新兴技术融合,进一步优化性能,并通过社区支持和开源生态建设不断完善。我们期待这些技术能够在更多的领域发挥重要作用,推动实时系统的发展和应用。

在实际应用中,开发者可以根据具体的需求和场景,选择合适的技术和配置方式。同时,持续关注技术的发展动态,不断学习和掌握新的知识和技能,才能更好地应对实时系统开发中的挑战,实现高效、稳定的实时应用。

【3D应力敏感度分析拓扑优化】【基于p-范数全局应力衡量的3D敏感度分析】基于伴随方法的有限元分析和p-范数应力敏感度分析(Matlab代码实现)内容概要:本文档介绍了基于伴随方法的有限元分析p-范数全局应力衡量的3D应力敏感度分析,并结合拓扑优化技术,提供了完整的Matlab代码实现方案。该方法通过有限元建模计算结构在载荷作用下的应力分布,采用p-范数对全局应力进行有效聚合,避免传统方法中应力约束过多的问题,进而利用伴随法高效求解设计变量对应力的敏感度,为结构优化提供关键梯度信息。整个流程涵盖了从有限元分析、应力评估到敏感度计算的核心环节,适用于复杂三维结构的轻量化高强度设计。; 适合人群:具备有限元分析基础、拓扑优化背景及Matlab编程能力的研究生、科研人员工程技术人员,尤其适合从事结构设计、力学仿真多学科优化的相关从业者; 使用场景及目标:①用于实现高精度三维结构的应力约束拓扑优化;②帮助理解伴随法在敏感度分析中的应用原理编程实现;③服务于科研复现、论文写作工程项目中的结构性能提升需求; 阅读建议:建议读者结合有限元理论优化算法知识,逐步调试Matlab代码,重点关注伴随方程的构建p-范数的数值处理技巧,以深入掌握方法本质并实现个性化拓展。
下载前必看:https://pan.quark.cn/s/9f13b242f4b9 Android 平板设备远程操控个人计算机的指南 Android 平板设备远程操控个人计算机的指南详细阐述了如何运用 Splashtop Remote 应用程序达成 Android 平板设备对个人计算机的远程操控。 该指南被划分为四个环节:首先,在个人计算机上获取并部署 Splashtop Remote 应用程序,并设定客户端密码;其次,在 Android 平板设备上获取并部署 Splashtop Remote 应用程序,并之建立连接至个人计算机的通道;再次,在 Splashtop Remote 应用程序中识别已部署个人计算机端软件的设备;最后,运用平板设备对个人计算机实施远程操控。 关键点1:Splashtop Remote 应用程序的部署配置* 在个人计算机上获取并部署 Splashtop Remote 应用程序,可通过官方网站或其他获取途径进行下载。 * 部署结束后,必须输入客户端密码,该密码在平板控制计算机时用作验证,密码长度至少为8个字符,且需包含字母数字。 * 在配置选项中,能够设定是否在设备启动时自动运行客户端,以及进行互联网搜索设置。 关键点2:Splashtop Remote 应用程序的 Android 版本获取部署* 在 Android 平板设备上获取并部署 Splashtop Remote 应用程序,可通过 Google Play Store 或其他获取途径进行下载。 * 部署结束后,必须输入客户端密码,该密码用于连接至个人计算机端软件。 关键点3:运用 Splashtop Remote 远程操控个人计算机* 在 Splashtop Remote 应用程序中识别...
先看效果: https://pan.quark.cn/s/7baef05d1d08 在信息技术范畴内,语音识别是一项核心的技术,它赋予计算机或设备解析和处理人类语音输入的能力。 本研究项目运用了MFCC(Mel Frequency Cepstral Coefficients)VQ(Vector Quantization)算法,借助VC++6.0的MFC(Microsoft Foundation Classes)库,开发出一个图形用户界面(GUI),从而达成基础的语音识别功能。 接下来将具体分析这些技术及其应用。 **MFCC特征提取**MFCC是语音信号处理中的一个标准方法,用于将复杂的语音波形转换成一组便于处理的数据参数。 MFCC模拟人类听觉系统对声音频率的感知模式,通过梅尔滤波器组对声音频谱进行分段处理,进而计算每个滤波器组的倒谱系数。 该过程包含以下环节:1. **预加重**:旨在削弱人声的低频响应部分,同时增强高频成分的强度。 2. **分帧和窗函数**:将语音信号分割成多个短时帧,并应用窗函数以降低帧帧之间的相互干扰。 3. **梅尔尺度滤波**:采用梅尔滤波器组对每一帧进行剖析,获取梅尔频率谱。 4. **取对数**:鉴于人耳对声音强度的感知呈现非线性特征,因此对梅尔频率谱取对数操作以更好地符合人类听觉系统。 5. **离散余弦变换(DCT)**:对对数谱实施DCT运算,提取主要特征,通常选取前12-20个系数作为MFCC特征。 6. **动态特性**:为了捕捉语音的时域变化特征,还可计算MFCC特征的差分值和二阶差分值。 **VQ识别算法**VQ是一种数据压缩方法,在语音识别领域中常用于特征矢量的量化处理。 其基本理念是将高维度的MFCC特征向量映射到一个小型、预...
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值