银行家算法

 银行家算法是资源和死锁避免的算法,由艾兹格·迪杰斯特拉(Edsger Dijkstra) 设计的算法用于测已确定总数量的资源分配的安全性,在决定是否该分配应该被允许并进行下去之前,通过“s-state”校验码测试资源分配活动期间产生死锁条件的可能性。 
    该算法是为为THE操作系统设计并且最在在EWD108描述。当一个新的进程进入系统时,进程必须声明所需每个资源实例最大的数量和类型。显然,资源数量不不能超过系统最大的资源数。与此同时,进程获得的资源必须在有限的时间内释放。

资源

对于银行家算法的实现,需要知道三件事: 

  • 每个进程所能获取的每种资源数量是多少[MAX] 
  • 每个进程当前所分配到的每种资源的数量是多少[ALLOCATED] 
  • 系统当前可分配的每种的资源数量是多少[AVAILABLE]

    只有当资源满足以下条件,资源才会被分配:

    1. request <= max, 也可设置错误条件,当进程所请求的资源超过最大的要求
    2. request <= available, 或者进 
      程一直等直到资源可分配

    一些资源在实际的系统被跟踪,如:内存,信号量以及接口。

        银行家算法名字源于该算法实际上是用于确保银行系统不会用尽系统资源,因为当银行系统不再满足所有客户的需求,系统将不会分配钱(看作资源)给客户,银行必须确保对钱的请求不会导致银行系统处于不安全状态。如果上述情况不会发生,则该情况下请求是被允许的,否则,客户必须等到其他客户往银行存进足够银行分配的资金。

    基本数据结构用于维护运行银行家算法: 
    用n表示系统资源数量,m表示系统资源类型。则我们需要以下的数据结构: 

  • Available: 长度为m的向量用来表示每种资源可分配的数量。如果available[j]=k, 资源类型为Rj可分配数量为k。 
  • Max: n * m矩阵,定义,每个进程最大的资源需求。如果Max[i,j]=k. 表明Pi对类型为Rj资源的请求为k. 
  • Allocation: n * m矩阵定义每个进程已分配到的每种资源的数量。如果Allocation[i,j] = k,进程Pi已分配到类型为Rj的资源数量为k。 
  • Need: n * m 矩阵表明每个进程所需的资源数量,如果Need[i,j] = k, 进程Pi需要至少得到k数量的资源Rj,才能完成任务。

    公式:Need[i,j] = Max[i,j] - Allocation[i,j]

    例子:

    系统资源总数: 
    A B C D 
    6 5 7 6

    系统可分配资源数: 
    A B C D 
    3  1 1 2

    进程 (当前分配到的资源数): 
        A B C D 
    P1 1 2 2 1 
    P2 1 0 3 3 
    P3 1 2 1 0

    进程 (最大资源需求数): 
        A B C D 
    P1 3 3 2 2 
    P2 1 2 3 4 
    P3 1 3 5 0

    Need= Max - Allocation 
    进程 (需要的资源数): 
        A B C D 
    P1 2 1 0 1 
    P2 0 2 0 1 
    P3 0 1 4 0

    安全和不安全状态

        如果该状态下所有进程都可以结束运行,则该状态是安全。因为系统无法知道什么时候一个进程结束运行,或有多少资源被进程请求,系统只是假设所有的进程最终会试图获取他们所规定的最大资源,并且在获得资源使用完之后会结束运行。在大多数的情况下,该假设是很合理的,因为系统不会特别的关心每个进程的运行多久(至少不是从死锁避免的角度)。

        对于该猜想,算法确定是否一个状态是安全通过找到一个猜想性的进程请求序列,允许所有进程获取最大的资源数并顺利结束运行。而任何无法达到上诉要求的的状态都是不安全的状态。

        我们可以得到之前例子的安全状态,只要能使每个进程获得最大资源并结束运行。

    1.P1 得到 2 A,1 B 和 1 D,达到进程需求的最大资源数 

  • [可分配资源:<3 1 1 2> - <2 1 0 1> = <1 0 1 1>] 
  • 系统当前有1 A, 0 B, 1 C, 和 1 D 资源可分配

    2.P1 结束运行,释放3 A, 3 B, 2 C, 和2 D资源给系统。 

  • [可分配资源:<1 0 1 1> - <3 3 4 4> = <4 3 3 3>] 
  • 系统当前有4 A, 3 B, 3 C, 和 3 D 资源可分配

    3.P2 结束运行,请求0 A, 2 B, 0 C, 和1 D资源,之后运行结束,释放资源给系统 

  • [可分配资源:<4 3 3 3> - <0 2 0 1> + <1 2 3 4>= <5 3 6 6>] 
  • 系统当前有5 A, 3 B, 6 C, 和 6 D 资源可分配

    4.P3 请求0 A, 1 B, 4 C, 和0 D资源,之后运行结束,释放资源给系统 

  • [可分配资源:<5 3 6 6> - <0 1 4 0> + <1 3 5 0>= <6 5 7 6>] 
  • 系统现在用所有的资源6 A, 5 B, 7 C 和 6 D

    5.由于所有的进程可以结束运行,该状态是安全的状态。

    请求

        当系统收到对资源请求信号时,系统运行银行家算法判断允许请求是否安全。

    1.该请求是否可以运行? 

  • 如果不允许,该请求则是不可行的,必须要么拒绝请求或插入到等待队列。 
    2.假设请求被允许 
    3.是否安全? 
  • 如果安全,请求授予 
  • 否则,要么拒绝或插入到等待队列

    不论系统拒绝请求或请求延迟或不安全请求都是系统的特殊决定。

    例子:

    从之前的例子开始,假设进程3请求2个单位的资源C。 
    1. 系统没有足够的资源C可以用于分配 
    2. 该请求被拒绝

    另一方面,假设进程3请求1单元资源C。 
    1. 系统有足够的资源分配 
    2. 请求允许 
    新的状态如下:

    系统可分配的资源 
           A B C D 
    Free 3 1 0 2 
    进程 (当前进程分配到资源): 
         A B C D 
    P1 1 2 2 1 
    P2 1 0 3 3 
    P3 1 2 2 0 
    进程(最大需求资源数): 
         A B C D 
    P1 3 3 2 2 
    P2 1 2 3 4 
    P3 1 3 5 0

    1. 判断是新的安全状态是否安全 
      1>P1 获得2 A,1 B, 和 1 D资源并运行结束 
      2>之后,P2 能获得2 B 和1 D资源并结束运行 
      3>最后P3 能获得1 B 和3 C资源并运行结束 
      4>因此,改新状态为安全的

    最后,从该状态开始,假设进程2请求1单元的资源B。 
    1.系统有足够的资源 
    2.假设所有的请求都允许,新状态如下:

    系统可分配的资源: 
           A B C D 
    Free 3 0 1 2 
    进程 (当前进程分配到资源): 
        A B C D 
    P1 1 2 2 1 
    P2 1 1 3 3 
    P3 1 2 1 0 
    进程(最大需求资源数): 
        A B C D 
    P1 3 3 2 2 
    P2 1 2 3 4 
    P3 1 3 5 0

    1.存在安全的状态吗?假设P1,P2,P3请求资源B 和 C。 

  • P1无法完成资源B的请求 
  • P2无法完成资源B的请求 
  • P3无法完成资源B的请求 
  • 没有进程能获得足够的资源结束运行,故该状态是不安全的。

    /*PROGRAM TO IMPLEMENT BANKER'S ALGORITHM
      *   --------------------------------------------*/
    #include <stdio.h>
    int curr[5][5], maxclaim[5][5], avl[5];
    int alloc[5] = {0, 0, 0, 0, 0};
    int maxres[5], running[5], safe=0;
    int count = 0, i, j, exec, r, p, k = 1;
    
    int main()
    {
        printf("\nEnter the number of processes: ");
        scanf("%d", &p);
    
        for (i = 0; i < p; i++) {
            running[i] = 1;
            count++;
        }
    
        printf("\nEnter the number of resources: ");
        scanf("%d", &r);
    
        printf("\nEnter Claim Vector:");
        for (i = 0; i < r; i++) { 
            scanf("%d", &maxres[i]);
        }
    
        printf("\nEnter Allocated Resource Table:\n");
        for (i = 0; i < p; i++) {
            for(j = 0; j < r; j++) {
                scanf("%d", &curr[i][j]);
            }
        }
    
        printf("\nEnter Maximum Claim Table:\n");
        for (i = 0; i < p; i++) {
            for(j = 0; j < r; j++) {
                scanf("%d", &maxclaim[i][j]);
            }
        }
    
        printf("\nThe Claim Vector is: ");
        for (i = 0; i < r; i++) {
            printf("\t%d", maxres[i]);
        }
    
        printf("\nThe Allocated Resource Table:\n");
        for (i = 0; i < p; i++) {
            for (j = 0; j < r; j++) {
                printf("\t%d", curr[i][j]);
            }
    
            printf("\n");
        }
    
        printf("\nThe Maximum Claim Table:\n");
        for (i = 0; i < p; i++) {
            for (j = 0; j < r; j++) {
                printf("\t%d", maxclaim[i][j]);
            }
    
            printf("\n");
        }
    
        for (i = 0; i < p; i++) {
            for (j = 0; j < r; j++) {
                alloc[j] += curr[i][j];
            }
        }
    
        printf("\nAllocated resources:");
        for (i = 0; i < r; i++) {
            printf("\t%d", alloc[i]);
        }
    
        for (i = 0; i < r; i++) {
            avl[i] = maxres[i] - alloc[i];
        }
    
        printf("\nAvailable resources:");
        for (i = 0; i < r; i++) {
            printf("\t%d", avl[i]);
        }
        printf("\n");
    
        //Main procedure goes below to check for unsafe state.
        while (count != 0) {
            safe = 0;
            for (i = 0; i < p; i++) {
                if (running[i]) {
                    exec = 1;
                    for (j = 0; j < r; j++) {
                        if (maxclaim[i][j] - curr[i][j] > avl[j]) {
                            exec = 0;
                            break;
                        }
                    }
                    if (exec) {
                        printf("\nProcess%d is executing\n", i + 1);
                        running[i] = 0;
                        count--;
                        safe = 1;
    
                        for (j = 0; j < r; j++) {
                            avl[j] += curr[i][j];
                        }
    
                        break;
                    }
                }
            }
            if (!safe) {
                printf("\nThe processes are in unsafe state.\n");
                break;
            } else {
                printf("\nThe process is in safe state");
                printf("\nAvailable vector:");
    
                for (i = 0; i < r; i++) {
                    printf("\t%d", avl[i]);
                }
    
                printf("\n");
            }
        }
    }
    
    /*SAMPLE  OUTPUT
    -----------------
    Enter the number of processes:5
    
    Enter the number of resources:4
    
    Enter Claim Vector:8 5 9 7
    
    Enter Allocated Resource Table:
    2 0 1 1
    0 1 2 1
    4 0 0 3
    0 2 1 0
    1 0 3 0
    
    Enter Maximum Claim Table:
    3 2 1 4
    0 2 5 2
    5 1 0 5
    1 5 3 0
    3 0 3 3
    
    The Claim Vector is:    8   5   9   7
    The Allocated Resource Table:
        2   0   1   1
        0   1   2   1
        4   0   0   3
        0   2   1   0
        1   0   3   0
    
    The  Maximum Claim Table:
        3   2   1   4
        0   2   5   2
        5   1   0   5
        1   5   3   0
        3   0   3   3
    
     Allocated resources:   7   3   7   5
     Available resources:   1   2   2   2
    
    Process3 is executing
    
     The process is in safe state
     Available vector:  5   2   2   5
    Process1 is executing
    
     The process is in safe state
     Available vector:  7   2   3   6
    Process2 is executing
    
     The process is in safe state
     Available vector:  7   3   5   7
    Process4 is executing
    
     The process is in safe state
     Available vector:  7   5   6   7
    Process5 is executing
    
     The process is in safe state
     Available vector:  8   5   9   7
    
     ---------------------------------------------------------*/
      
      
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188

    局限

    同其他的算法相似,银行家算法运行时也有一些局限。特别是,必须知道每个进程所能请求的资源。在大多数系统,该信息是不可知的,使的无法顺利运行银行家算法。而且也无法去假设进程数量是不变的,因为大多数的系统的进程数量是动态变化的。再者,对于正确的算法,进程会释放其全部的资源(当进程结束运行),然而对于实际中的系统则是不可行。为了资源的释放等上数小时甚至几天,通常是不可接受的。

操作系统课的实验(银行家算法)#include "malloc.h"   #include "stdio.h"   #include "stdlib.h"   #define alloclen sizeof(struct allocation)   #define maxlen sizeof(struct max)   #define avalen sizeof(struct available)   #define needlen sizeof(struct need)   #define finilen sizeof(struct finish)   #define pathlen sizeof(struct path)   struct allocation   {   int value;   struct allocation *next;   };   struct max   {   int value;   struct max *next;   };   struct available /*可用资源数*/   {   int value;   struct available *next;   };   struct need /*需求资源数*/   {   int value;   struct need *next;   };   struct path   {   int value;   struct path *next;   };   struct finish   {   int stat;   struct finish *next;   };   int main()   {   int row,colum,status=0,i,j,t,temp,processtest;   struct allocation *allochead,*alloc1,*alloc2,*alloctemp;   struct max *maxhead,*maxium1,*maxium2,*maxtemp;   struct available *avahead,*available1,*available2,*workhead,*work1,*work2,*worktemp,*worktemp1;   struct need *needhead,*need1,*need2,*needtemp;   struct finish *finihead,*finish1,*finish2,*finishtemp;   struct path *pathhead,*path1,*path2;   printf("\n请输入系统资源的种类数:");   scanf("%d",&colum);   printf("请输入现时内存中的进程数:");   scanf("%d",&row);   printf("请输入已分配资源矩阵:\n");   for(i=0;i<row;i++)   {   for (j=0;jnext=alloc2->next=NULL;   scanf("%d",&allochead->value);   status++;   }   else   {   alloc2=(struct allocation *)malloc(alloclen);   scanf("%d,%d",&alloc2->value);   if(status==1)   {   allochead->next=alloc2;   status++;   }   alloc1->next=alloc2;   alloc1=alloc2;   }   }   }   alloc2->next=NULL;   status=0;   printf("请输入最大需求矩阵:\n");   for(i=0;i<row;i++)   {   for (j=0;jnext=maxium2->next=NULL;   scanf("%d",&maxium1->value);   status++;   }   else   {   maxium2=(struct max *)malloc(maxlen);   scanf("%d,%d",&maxium2->value);   if(status==1)   {   maxhead->next=maxium2;   status++;   }   maxium1->next=maxium2;   maxium1=maxium2;   }   }   }   maxium2->next=NULL;   status=0;   printf("请输入现时系统剩余的资源矩阵:\n");   for (j=0;jnext=available2->next=NULL;   work1->next=work2->next=NULL;   scanf("%d",&available1->value);   work1->value=available1->value;   status++;   }   else   {   available2=(struct available*)malloc(avalen);   work2=(struct available*)malloc(avalen);   scanf("%d,%d",&available2->value);   work2->value=available2->value;   if(status==1)   {   avahead->next=available2;   workhead->next=work2;   status++;   }   available1->next=available2;   available1=available2;   work1->next=work2;   work1=work2;   }   }   available2->next=NULL;   work2->next=NULL;   status=0;   alloctemp=allochead;   maxtemp=maxhead;   for(i=0;i<row;i++)   for (j=0;jnext=need2->next=NULL;   need1->value=maxtemp->value-alloctemp->value;   status++;   }   else   {   need2=(struct need *)malloc(needlen);   need2->value=(maxtemp->value)-(alloctemp->value);   if(status==1)   {   needhead->next=need2;   status++;   }   need1->next=need2;   need1=need2;   }   maxtemp=maxtemp->next;   alloctemp=alloctemp->next;   }   need2->next=NULL;   status=0;   for(i=0;inext=finish2->next=NULL;   finish1->stat=0;   status++;   }   else   {   finish2=(struct finish*)malloc(finilen);   finish2->stat=0;   if(status==1)   {   finihead->next=finish2;   status++;   }   finish1->next=finish2;   finish1=finish2;   }   }   finish2->next=NULL; /*Initialization compleated*/   status=0;   processtest=0;   for(temp=0;temp<row;temp++)   {   alloctemp=allochead;   needtemp=needhead;   finishtemp=finihead;   worktemp=workhead;   for(i=0;istat==0)   {   for(j=0;jnext,worktemp=worktemp->next)   if(needtemp->valuevalue)   processtest++;   if(processtest==colum)   {   for(j=0;jvalue+=alloctemp->value;   worktemp1=worktemp1->next;   alloctemp=alloctemp->next;   }   if(status==0)   {   pathhead=path1=path2=(struct path*)malloc(pathlen);   path1->next=path2->next=NULL;   path1->value=i;   status++;   }   else   {   path2=(struct path*)malloc(pathlen);   path2->value=i;   if(status==1)   {   pathhead->next=path2;   status++;   }   path1->next=path2;   path1=path2;   }   finishtemp->stat=1;   }   else   {   for(t=0;tnext;   finishtemp->stat=0;   }   }   else   for(t=0;tnext;   alloctemp=alloctemp->next;   }   processtest=0;   worktemp=workhead;   finishtemp=finishtemp->next;   }   }   path2->next=NULL;   finishtemp=finihead;   for(temp=0;tempstat==0)   {   printf("\n系统处于非安全状态!\n");   exit(0);   }   finishtemp=finishtemp->next;   }   printf("\n系统处于安全状态.\n");   printf("\n安全序列为: \n");   do   {   printf("p%d ",pathhead->value);   }   while(pathhead=pathhead->next);   printf("\n");   return 0;   } #include "string.h" #include #include #define M 5 #define N 3 #define FALSE 0 #define TRUE 1 /*M个进程对N类资源最大资源需求量*/ int MAX[M][N]={{7,5,3},{3,2,2},{9,0,2},{2,2,2},{4,3,3}}; /*系统可用资源数*/ int AVAILABLE[N]={10,5,7}; /*M个进程对N类资源最大资源需求量*/ int ALLOCATION[M][N]={{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0}}; /*M个进程已经得到N类资源的资源量 */ int NEED[M][N]={{7,5,3},{3,2,2},{9,0,2},{2,2,2},{4,3,3}}; /*M个进程还需要N类资源的资源量*/ int Request[N]={0,0,0}; void main() { int i=0,j=0; char flag='Y'; void showdata(); void changdata(int); void rstordata(int); int chkerr(int); showdata(); while(flag=='Y'||flag=='y') { i=-1; while(i=M) { printf("请输入需申请资源的进程号(从0到"); printf("%d",M-1); printf(",否则重输入!):"); scanf("%d",&i); if(i=M)printf("输入的进程号不存在,重新输入!\n"); } printf("请输入进程"); printf("%d",i); printf("申请的资源数\n"); for (j=0;jNEED[i][j]) { printf("进程"); printf("%d",i); printf("申请的资源数大于进程"); printf("%d",i); printf("还需要"); printf("%d",j); printf("类资源的资源量!申请不合理,出错!请重新选择!\n"); /*printf("申请不合理,出错!请重新选择!\n");*/ flag='N'; break; } else { if(Request[j]>AVAILABLE[j]) { printf("进程"); printf("%d",i); printf("申请的资源数大于系统可用"); printf("%d",j); printf("类资源的资源量!申请不合理,出错!请重新选择!\n"); /*printf("申请不合理,出错!请重新选择!\n");*/ flag='N'; break; } } } if(flag=='Y'||flag=='y') { changdata(i); if(chkerr(i)) { rstordata(i); showdata(); } else showdata(); } else showdata(); printf("\n"); printf("是否继续银行家算法演示,按'Y'或'y'键继续,按'N'或'n'键退出演示: "); scanf("%c",&flag); } } void showdata() { int i,j; printf("系统可用的资源数为:\n"); printf(" "); for (j=0;j<N;j++){ printf(" 资源"); printf("%d",j); printf(":"); printf("%d",AVAILABLE[j]); /*printf("\n");*/ /* cout<<endl; // cout<<"各进程资源的最大需求量:"<<endl<<endl; // for (i=0;i<M;i++) // { // cout<<"进程"<<i<<":"; // for (j=0;j<N;j++)cout<<" 资源"<<j<<": "<<MAX[i][j]; // cout<<endl; */ } printf("\n"); printf("各进程还需要的资源量:\n"); for (i=0;i<M;i++) { printf(" 进程"); printf("%d",i); printf(":"); for (j=0;j<N;j++){ printf("资源"); printf("%d",j); printf(":"); printf("%d",NEED[i][j]); /*printf("\n");*/ } printf("\n"); } printf("各进程已经得到的资源量: \n"); for (i=0;i<M;i++) { printf(" 进程"); printf("%d",i); /*printf(":\n");*/ for (j=0;j<N;j++){ printf("资源"); printf("%d",j); printf(":"); printf("%d",ALLOCATION[i][j]); /*printf("\n");*/ } printf("\n"); } } void changdata(int k) { int j; for (j=0;j<N;j++) { AVAILABLE[j]=AVAILABLE[j]-Request[j]; ALLOCATION[k][j]=ALLOCATION[k][j]+Request[j]; NEED[k][j]=NEED[k][j]-Request[j]; } }; void rstordata(int k) { int j; for (j=0;j<N;j++) { AVAILABLE[j]=AVAILABLE[j]+Request[j]; ALLOCATION[k][j]=ALLOCATION[k][j]-Request[j]; NEED[k][j]=NEED[k][j]+Request[j]; } }; int chkerr(int s) { int WORK,FINISH[M],temp[M]; int i,j,k=0; for(i=0;i<M;i++)FINISH[i]=FALSE; for(j=0;j<N;j++) { WORK=AVAILABLE[j]; i=s; while(i<M) { if (FINISH[i]==FALSE&&NEED[i][j]<=WORK) { WORK=WORK+ALLOCATION[i][j]; FINISH[i]=TRUE; temp[k]=i; k++; i=0; } else { i++; } } for(i=0;i<M;i++) if(FINISH[i]==FALSE) { printf("\n"); printf("系统不安全!!! 本次资源申请不成功!!!\n"); printf("\n"); return 1; } } printf("\n"); printf("经安全性检查,系统安全,本次分配成功。\n"); printf("\n"); printf(" 本次安全序列:"); for(i=0;i"); } printf("\n"); return 0; }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值