银行家算法

本文深入探讨了艾兹格·迪杰斯特拉设计的银行家算法,用于解决资源分配的安全性和死锁问题。文章详细介绍了算法的基本原理、实现步骤以及关键数据结构,包括资源数量、可用资源、进程需求和安全状态判断。同时,通过实例展示了如何利用银行家算法确保系统资源的有效分配和避免死锁。

    银行家算法是资源和死锁避免的算法,由艾兹格·迪杰斯特拉(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
    
     ---------------------------------------------------------*/

    局限

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

    原文来自维基百科:http://en.wikipedia.org/wiki/Banker’s_algorithm
    初次翻译,有不足之处,欢迎指正,转载请注明出处,谢谢!

<think> 首先,用户的问题是关于理解一个特定的正则表达式:/^(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9]).{8,}$。我需要解释这个正则表达式的含义。 回顾系统级指令: - 所有行内数学表达式必须使用$...$格式。 - 独立公式必须使用$$...$$格式并单独成段。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 回答中引用的段落末尾自然地添加引用标识。 - 回答结构清晰,帮助用户逐步解决问题。 - 最后,生成相关问题。 用户提供了三个引用: - 引用[1]:关于常见正则表达式,如正浮点数。 - 引用[2]:包含各种正则表达式的例子,如字母数字下划线字符串、整数、浮点数、中文字符、身份证号等。 - 引用[3]:关于正则表达式的简化建议。 但用户说这些引用仅供参考,我应该基于用户的问题来回答。用户的问题是解释正则表达式/^(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9]).{8,}$的含义。 所以,我需要解析这个正则表达式。 分解正则表达式- /^:表示字符串的开始。 - (?=.*[A-Z]):这是一个正向先行断言(positive lookahead)。意思是:字符串中必须包含至少一个大写字母(A-Z)。 - (?=.*[a-z]):另一个正向先行断言,表示字符串中必须包含至少一个小写字母(a-z)。 - (?=.*[0-9]):另一个正向先行断言,表示字符串中必须包含至少一个数字(0-9)。 - .{8,}:表示任意字符(除换行符外)至少8次。意思是字符串长度至少为8个字符。 - $:表示字符串的结束。 所以,整体来看,这个正则表达式匹配的字符串必须: 1. 包含至少一个大写字母。 2. 包含至少一个小写字母。 3. 包含至少一个数字。 4. 长度至少为8个字符。 这通常用于密码强度验证,要求密码有大小写字母、数字,并且长度至少8位。 现在,构建回答: - 使用中文。 - 结构清晰:逐步解释。 - 引用相关部分:用户提供了引用,但它们是关于其他正则表达式的。我可以提到引用[2]中有类似的正则表达式例子,比如强密码的表达式,但用户的具体表达式不同。引用[2]中有类似的东西:/^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{6,15}$/,这很相似,但长度不同。 在引用[2]中:强密码:必须包含数字、字母,字符长度为6~15位 /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{6,15}$/ 或 /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])[0-9a-zA-Z]{6,15}$/。 用户的正则是/^(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9]).{8,}$,长度至少8,没有上限,并且使用.*允许任何字符。 所以,在回答中,我可以引用这个。 引用[3]是关于简化正则表达式的建议,但可能不直接相关。 回答结构: 1. 介绍正则表达式的整体目的:用于验证密码强度。 2. 分解表达式部分: - ^$:表示整个字符串。 - (?=.*[A-Z]):解释先行断言的含义。 - 类似地解释其他部分。 - .{8,}:长度要求。 3. 总结匹配的条件。 4. 自然地添加引用:例如,在解释先行断言时,可以提到引用中的类似例子。 引用标识:在引用的段落末尾添加[^n]。 最后,生成相关问题。 相关问题应该基于这个主题,比如: 1. 如何使用这个正则表达式在代码中? 2. 这个正则表达式的局限性是什么? 3. 如何修改它来添加特殊字符要求? 4. 相关的正则表达式例子。 确保LaTeX:在回答中,如果有数学表达式,比如.*[A-Z],这不算数学表达式,所以不需要用$...$。但如果有像范围或计数,可能不需要。指令是针对数学表达式的,所以这里可能不适用。 在引用中,用户有像^[1-9]\d*\.\d*|0\.\d*[1-9]\d*$这样的表达式,但没有要求用LaTeX格式。指令说“所有行内数学表达式(包括变量、不等式、方程等)必须使用$...$格式”,但正则表达式不是数学表达式,所以我应该直接写正则表达式。 在回答中,我会直接写正则表达式代码,用反引号表示代码块或内联代码。 指令有示例:在“快速排序”例子中,有代码块用```python```。 所以,我可以将正则表达式放入代码块。 回答步骤: 1. 解释整体含义。 2. 分解每个部分。 3. 给出示例匹配的字符串。 4. 引用相关资源。 5. 生成相关问题。 用中文。 </think> ### 正则表达式 `/^(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9]).{8,}$` 的含义解析 这个正则表达式主要用于验证密码强度,要求字符串满足特定的复杂度条件。以下我将逐步分解其结构,帮助您理解每个部分的含义。整个表达式的核心是使用**正向先行断言(positive lookahead)** 来确保字符串中包含大写字母、小写字母和数字,同时要求最小长度。正则表达式语法可参考站内引用中的常见模式[^2]。 #### 1. **整体结构** - `/^ ... $/`:这表示正则表达式匹配整个字符串,从开头 (`^`) 到结尾 (`$`)。例如,字符串 `"Abc12345"` 会被匹配,但 `" Abc12345"`(开头有空格)则不会,因为空格导致开头不匹配。 - 表达式由多个部分组成: - 三个正向先行断言 `(?=...)`:用于检查字符串是否满足某些条件,但不消耗字符(即不移动匹配位置)。 - `.`:匹配任意单个字符(除换行符外)。 - `{8,}`:表示前面的模式(这里是 `.`)至少重复 8 次,即字符串长度至少为 8 个字符。 - **简言之**:这个正则表达式要求字符串**必须同时包含至少一个大写字母、至少一个小写字母、至少一个数字,且总长度不少于 8 个字符**。它常用于密码策略中,确保密码强度。 #### 2. **分解每个部分** - `(?=.*[A-Z])`: - `(?= ... )` 是正向先行断言,表示“字符串必须满足括号内的条件”,但不计入匹配位置。 - `.*`:匹配零个或多个任意字符(`.` 表示任意字符,`*` 表示重复零次或多次)。 - `[A-Z]`:匹配一个大写字母(A 到 Z)。 - **含义**:字符串中必须包含至少一个大写字母。例如,在 `"abc123"` 中不满足(没有大写字母),而 `"Abc123"` 满足。 - 类似用法在引用[2]中的“强密码”例子中出现过(如 `/^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{6,15}$/`)[^2]。 - `(?=.*[a-z])`: - 结构同上,但 `[a-z]` 匹配一个小写字母(a 到 z)。 - **含义**:字符串中必须包含至少一个小写字母。例如,`"ABC123"` 不满足(没有小写字母),而 `"Abc123"` 满足。 - `(?=.*[0-9])`: - `[0-9]` 匹配一个数字(09)。 - **含义**:字符串中必须包含至少一个数字。例如,`"Abcdefg"` 不满足(没有数字),而 `"Abc123"` 满足。 - `.{8,}`: - `.` 匹配任意字符。 - `{8,}` 表示前面的 `.` 至少重复 8 次,即字符串长度至少为 8 个字符。 - **含义**:整个字符串的最小长度为 8。例如,`"Abc123"`(长度 6)不满足,而 `"Abc12345"`(长度 8)满足。 #### 3. **组合效果和示例** - **匹配条件总结**: - 至少一个大写字母(A-Z)。 - 至少一个小写字母(a-z)。 - 至少一个数字(0-9)。 - 长度至少 8 个字符(允许更长)。 - 字符类型不限(因为 `.` 匹配任意字符,包括符号如 `!@#$`)。 - **有效匹配示例**: - `"Password123"`:包含大写 P、小写 assword、数字 123,长度 11。 - `"Abc!12345"`:包含大写 A、小写 bc、数字 12345,以及符号 `!`,长度 9- **无效匹配示例**: - `"password"`:缺少大写字母和数字。 - `"PASSWORD123"`:缺少小写字母。 - `"Abc123"`:长度不足 8。 - `"!@#$%^&*"`:缺少字母和数字。 这个表达式确保了密码的基础强度,但未要求特殊字符(如符号),您可以根据需求扩展。类似的正则表达式设计原则在引用[3]中提到,强调“宁简勿繁”,即拆解复杂条件为多个简单断言以提升可读性和效率[^3]。 #### 4. **实际应用** - 在编程中,这个正则表达式可用于表单验证(如密码输入框)。例如,在 JavaScript 中: ```javascript const regex = /^(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9]).{8,}$/; console.log(regex.test("Abc12345")); // 输出 true console.log(regex.test("abc1234")); // 输出 false(缺少大写字母) ``` - 优点:使用先行断言能高效检查多个条件,无需嵌套或复杂逻辑。 - 局限性:它不检查字符类型重复(如多个数字),或特殊字符要求。如果需更严格规则(如包含符号),可追加断言,例如添加 `(?=.*[!@#$%^&*])`。 如果您有更多上下文(如具体代码实现),我可以提供更针对性的帮助。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值