理解进程调度时机跟踪分析进程调度与进程切换的过程

进程调度算法论文!! 通过优先权法和轮转算法的模拟加深对进程概念和进程调度过程的理解,掌握进程状态之间的切换,同时掌握进程调度算法的实现方法和技巧。 要求: 1.用C语言或C++语言来实现对n个进程采用优先权优先算法以及轮转算法的进程调度。 2.每个用来标识进程的进程控制块PCB用结构来描述,包括以下字段: (1)进程优先数ID,其中0为闲逛进程,用户进程的标识数为1,2,3…。 (2)进程优先级Priority,闲逛进程(idle)的优先级为0,用户进程的优先级大于0,且随机产生,优先数越大,优先级越高。 (3)进程占用的CPU时间CPUtime,进程每运行一次,累计值等于4。 (4)进程总共需要运行时间Alltime,利用随机函数产生。 (5)进程状态,0:就绪态;1:运行态;2:阻塞态。 (6)队列指针next,用来将多个进程控制块PCB链接为队列。 3.优先数改变的原则 (1)进程在就绪队列中每呆一个时间片,优先数增加1。 (2)进程每运行一个时间片,优先数减3。 4.在调度前,系统中拥有的进程数PCB_number由键盘输入,经初始化后,所有的进程控制块PCB链接成就绪队列。其中它们的初始化状态如下: This is an example for priority processing : Input the number of the PCB to be started :1 PCB: ID priority CPUtime ALLtime State 5 86 4 64 ready 1 32 20 68 ready 6 59 0 47 ready 2 18 20 62 ready 4 86 4 6 ready 7 72 4 51 ready 8 76 0 60 ready 9 4 4 19 ready 13 94 12 19 ready 16 88 12 24 ready 5.为了清楚地观察诸进程的调度过程,程序应将每个时间片内的进程的情况显示出来,参照输出格式如下所示: This is an example for priority processing : Input the number of the PCB to be started : PCB: ID priority CPUtime ALLtime State 1 42 0 68 ready 建立: Creating -> ready 1 41 4 68 running 变迁1:ready -> running 1 41 0 68 blocked 变迁2:running -> blocked 1 41 0 68 ready 变迁4:running -> ready The idle prcess is running! 变迁1:ready -> running The idle prcess is completed! 销毁: running -> Destroy The idle prcess is running! 变迁1:ready -> running The idle prcess is completed! 销毁: running -> Destroy The idle prcess is running! 变迁1:ready -> running 立即下载

“郭孟琦 + 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000 ”


貌似是最后一周课了,竟然坚持下来了!!!!


1、在内核代码中搜索schedule()函数,看都是哪里调用了schedule(),判断我们课程内容中的总结是否准确;


一搜吓了一大跳,

Searched full:schedule (Results 1 - 25 of 1213) sorted by relevance

看来直接挨个看是不太实际了,这里我重点挑出了之前的课程内容中出现的schedule


想了想发现这实际上就是探究linux进程调度的时机

Linux进程调度时机主要有:

1、进程状态转换的时刻:进程终止、进程睡眠;

2、当前进程的时间片用完时(current->counter=0);

3、设备驱动程序

4、进程从中断、异常及系统调用返回到用户态时;



时机1,进程要调用sleep()或exit()等函数进行状态转换,这些函数会主动调用调度程序进行进程调度;


时机2,由于进程的时间片是由时钟中断来更新的,因此,这种情况和时机4是一样的。


时机3,当设备驱动程序执行长而重复的任务时,直接调用调度程序。在每次反复循环中,驱动程序都检查need_resched的值,如果必要,则调用调度程序schedule()主动放弃CPU。


时机4,在system_call的结尾调用

596work_resched:
597	call schedule
598	LOCKDEP_SYS_EXIT

2、使用gdb跟踪分析一个schedule()函数

在系统调用结束后

确实调用了schedule,在跟踪时无法直接追踪汇编函数switch_to,因此还是直接分析代码吧

#define switch_to(prev, next, last)					\
32do {									\
33	/*								\
34	 * Context-switching clobbers all registers, so we clobber	\
35	 * them explicitly, via unused output variables.		\
36	 * (EAX and EBP is not listed because EBP is saved/restored	\
37	 * explicitly for wchan access and EAX is the return value of	\
38	 * __switch_to())						\
39	 */								\
40	unsigned long ebx, ecx, edx, esi, edi;				\
41									\
42	asm volatile("pushfl\n\t"		/* save    flags */	\
43		     "pushl %%ebp\n\t"		/* save    EBP   */	\
44		     "movl %%esp,%[prev_sp]\n\t"	/* save    ESP   */ \
45		     "movl %[next_sp],%%esp\n\t"	/* restore ESP   */ \
46		     "movl $1f,%[prev_ip]\n\t"	/* save    EIP   */	\
47		     "pushl %[next_ip]\n\t"	/* restore EIP   */	\
48		     __switch_canary					\
49		     "jmp __switch_to\n"	/* regparm call  */	\
50		     "1:\t"						\
51		     "popl %%ebp\n\t"		/* restore EBP   */	\
52		     "popfl\n"			/* restore flags */	\
53									\
54		     /* output parameters */				\
55		     : [prev_sp] "=m" (prev->thread.sp),		\
56		       [prev_ip] "=m" (prev->thread.ip),		\
57		       "=a" (last),					\
58									\
59		       /* clobbered output registers: */		\
60		       "=b" (ebx), "=c" (ecx), "=d" (edx),		\
61		       "=S" (esi), "=D" (edi)				\
62		       							\
63		       __switch_canary_oparam				\
64									\
65		       /* input parameters: */				\
66		     : [next_sp]  "m" (next->thread.sp),		\
67		       [next_ip]  "m" (next->thread.ip),		\
68		       							\
69		       /* regparm parameters for __switch_to(): */	\
70		       [prev]     "a" (prev),				\
71		       [next]     "d" (next)				\
72									\
73		       __switch_canary_iparam				\
74									\
75		     : /* reloaded segment registers */			\
76			"memory");					\
77} while (0)

这一过程非常 像一个超简单的系统内核 中的切换过程

1、新进程执行过,对于执行过的进程,只要保存好现在的现场(ebp存入堆栈中,esp(指向刚刚存进去的ebp)放入之前的thread结构体的sp中,eip放入thread结构体的ip中),恢复刚才的现场,也就是将新进程的eip,esp,ebp放出来。esp是直接从sp中赋给esp,eip从ip放入栈再通过ret弹出来(因为eip不能被直接修改),此时esp是指向刚才的ebp的(想不明白可以看esp存到sp里时指的是谁?)。但是弹出ebp这个过程要在ret之后,因为那个eip存的时候是指的1:,新的进程自然就会在它的1:处恢复

总结:学习完这门课 对堆栈 进程 有了很深刻的认识,也解决了ucos学习中不理解的很多问题。

论文《LINUX进程调度分析》 论文《LINUX进程调度分析》,和大家分享~ 立即下载

相关推荐

【首份】2023年30米分辨率土地利用遥感监测数据

为了恢复和重建我国土地利用变化的现代过程,更好地预测、预报土地利用变化趋势,地球资源数据云以美国陆地卫星Landsat 遥感影像数据作为主信息源,结合Sentinel系列数据,通过人工目视解译和机器学习方法,建立了国家尺度1:10 万比例尺多时期土地利用/土地覆盖遥感监测数据库(CNLUCC)因早期Landsat数据时空覆盖缺失,1972-1977年合成第一期数据,1978-1985年合成第二期数据,1986年起每年度生成一期数据。投影:Albers正轴等面积双标准纬线圆锥投影南标准纬线:25°N。

地球资源数据云的官方博客 3669

【进程调度】模拟进程调度的过程

1.目的和要求 通过这次实验,理解进程调度的过程,进一步掌握进程状态的转变、进程调度的策略,进一步体会多道程序并发执行的特点,并分析具体的调度算法的特点,掌握对系统性能的评价方法。 2.实验内容 阅读教材《计算机操作系统》第二章和第三章,掌握进程管理及调度相关概念和原理。 编写程序模拟实现进程的轮转法调度过程,模拟程序只对PCB进行相应的调度模拟操作,不需要实际程序。假设初始状态为:有n个

cutter_point的专栏 9998

串口调试神器诞生记:我是如何用Cursor+AI自动生成C#上位机的(含VSCode插件清单)

本文详细介绍了如何利用Cursor和AI技术快速开发C#上位机程序,实现高效的串口通讯调试。从开发环境搭建到代码自动生成,再到性能优化和功能增强,全面展示了AI辅助开发在串口调试中的实际应用和显著效率提升。

weixin_28340315的博客 299

Linux内核简单分析(2)——进程调度与切换

进程的调度与切换是一个很复杂的话题,这里我更关心内核是如何实现的,而不是使用了什么策略,所以只讲进程的组织和切换方式,而对调度程序的实现和算法不作分析。 如何组织进程? 回顾一下进程的task_struct结构,在里面有一个struct list_head run_list;字段,内核通过这个run_list将处于TASK_RUNNING状态的进程连成一个链表,而处于睡眠状态的进程则处于另一个等待...

silence1772的博客 982

超酷炫,Python实现交通数据可视化!

此时输出的栅格化参数params的内容存储了栅格坐标系的原点坐标(slon、slat)、单个栅格的经纬度长宽 (deltalon、deltalat)、栅格的旋转角度(theta)、栅格的形状(method参数,其值可以是方形rect、三角形tri和六边形hexa)以及栅格的大小(gridsize参数,单位为米)。Python所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。今天分享一次Python交通数据分析与可视化的实战!

m0_59236127的博客 1696

PWM(脉宽调制)技术详解:从基础到应用实践示例

PWM(脉宽调制)技术是嵌入式系统中一项重要的控制技术,通过调节脉冲宽度来实现对模拟设备的精准控制。从LED亮度到电机速度,PWM的应用场景非常广泛。对于嵌入式学习者来说,理解PWM的工作原理、掌握其配置方法,不仅能提升编程能力,还能为更多复杂系统的开发打下坚实的基础。

SpringWJN的博客 6325

浅谈 进程调度的时机和进程切换

罗晓波 + 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000 本周学习了对于进程调度的时机和进程切换,照旧,从一个小实验开始本周的分析和总结,实验环境使用实验楼。 一、实验:跟踪进程调度函数 首先,启动menuOS之后,在schedule()函数处打个断点,来跟踪一下: 进程的

lxbql121的专栏 877

LWIP协议栈在STM32H7上的内存优化实战:如何用32KB RAM实现稳定千兆以太网通信

本文深入探讨了在STM32H7微控制器上,如何通过内存优化策略,在仅32KB的D2 SRAM中稳定运行LWIP协议栈以实现千兆以太网通信。文章详细分析了STM32H7的内存架构、LWIP的内存消耗瓶颈,并提供了从描述符表与PBUF池精确分配、链接脚本修改到MPU区域划分的一整套实战优化方案,旨在解决大数据量传输卡死等常见配置问题。

gg901的博客 603

理解进程调度时机跟踪分析进程调度与进程切换的过程(Linux)

----------------------------------------------------------------------------------- 理解进程调度时机跟踪分析进程调度与进程切换的过程 ---------------------------------------------------------------------------------

NaiveOrange的博客 1978

【k8s实战】 在离线项目混部 通过kubeflow(tf-operator)部署TensorFlow机器学习任务+prometheus/grafana监控资源使用全过程(最新 图文)

目录在离线混合部署概念最新版kubeflow部署TensorFlow部署二级目录三级目录 在离线混合部署概念 先举一个例子,众所周知的天猫双十一当天的流量非常之大,那么就需要成百上千台服务器构成一个超大集群来提供计算能力,但是双十一过去之后,集群资源就面临着浪费的局面。假设业务分为在线和离线两种模式:在线任务需要资源相对较少,但要求响应时间短;离线任务则不需要对任务进行迅速响应,但是计算量相对较大、占用资源多。那么我们应该怎么在K8S集群上完成这两种业务的部署、并且使得CPU利用率始终维持在一个比较高的水平

Eros1on的博客 1545

Universal Robot——在Gazebo中模拟UR5机器人

今天的目标是在Gazebo安装我们的ur5机器人。Gazebo是一个流行的模拟工具,它不仅可以让你像在Rviz中一样可视化你的机器人,而且还内置了一个物理引擎。这样你就可以在更真实的环境中测试你的机器人应用程序。我们将查看我们需要的属性 添加对我们的机器人——我们的order的描述,以模拟它以及如何在Gazebo中生成我们的机器人。

如果想成为中心,那么就到中心去吧。 1969

Linux内核分析之理解进程调度时机跟踪分析进程调度与进程切换的过程

SA16225055冯金明    原创作品转载请注明出处  《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000 实验内容 实验要求: 理解Linux系统中进程调度的时机,可以在内核代码中搜索schedule()函数,看都是哪里调用了schedule(),判断我们课程内容中的总结是否准确;

Kimi_ming的博客 881

从自然语言到PCB设计:DeepSeek与Altium协同自动化实战指南

摘要:在电子设计领域,将自然语言需求转化为PCB设计图是实现自动化设计的重要目标。受限于当前NLP和EDA技术,通过DeepSeek直接生成完整PCB设计图尚无法实现,但在设计辅助环节已展现实用价值。本文深入分析技术可行性,提出"自然语言→设计约束→脚本生成→人工验证"的人机协同工作流。通过28个完整代码示例、12张技术图表及5个工程案例,详细展示DeepSeek解析需求、生成设计约束,并结合Altium Designer API实现元件放置、规则设置、DRC校验的全流程。

专注于人工智能、软件开发、工控自动化、工厂数字化及智能化等领域,希望和大家共同进步! 1759

理解进程调度时机跟踪分析进程调度与进程切换的过程-基于实验楼

理解进程调度时机跟踪分析进程调度与进程切换的过程进程调度schedule函数进程调度时机gdb调试schedule()函数总结 进程调度 schedule函数 Linux内核通过schedule函数来实现进程的调度,schedule详细代码见代码。schedule函数在运行队列中找到一个进程并将CPU分配给它。换句话说调用schedule函数一次就是进程调度一次。 进程调度有两种方法 方法1是进程主动调用schedule(),如进程调用阻塞的系统调用等待外设或主动睡眠等,最终都会在内核中调用到schedu

weixin_44240981的博客 842

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

linux 进程调度时机,理解进程调度时机跟踪分析进程调度与进程切换的过程

实验准备环境进行调试进程上下文切换相关代码分析#define switch_to(prev, next, last)do {/** Context-switching clobbers all registers, so we clobber* them explicitly, via unused output variables.* (EAX and EBP is not listed bec...

weixin_39955149的博客 134

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

上一篇: Linux内核如何装载和启动一个可执行程序
下一篇: Linux内核分析课程考试主观题
oCoreCode
博客等级 码龄14年 1粉丝 9原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值