死锁优化

按时间段模拟资源申请、特殊进程的放弃与抢夺,并用状态循环判断无法结束的死锁。

OJ: shumeng

题目 ID: CSP202605C

难度:未知

标签:模拟状态机哈希多进程调度

日期: 2026-07-31 16:22

形式化题目

nn 个进程、mm 种资源,每个进程从第 stist_i 段首开始活动,按任务列表依次申请资源并运行,任务长度 ti,jt_{i,j} 段。每段分为段首(申请)、段中(收益)、段末(推进/释放)。

  • 同一资源同一段首被多进程申请时:资源空闲则编号最小者成功,否则全部失败;
  • A 类:连续 ww 次申请失败后,在段末释放自己占有的全部资源,继续等待;
  • B 类:连续 ww 次申请失败后,直接放弃该资源并进入运行;
  • C 类:连续 ww 次申请失败后在段首强行抢夺,多个 C 同时抢夺时编号最大者成功。

运行中的进程每段获得等于其当前持有资源数的收益。输出每个进程的总收益与运行段数;若系统因死锁被强制结束,输出 -1

思路

三个阶段逐一模拟

每段严格按“段首申请 → 段中收益 → 段末推进和释放”推进。进程维护状态、当前任务、等待开始时间、剩余段数与收益;资源维护当前占有者。

段首的统一处理

同一资源的申请必须收集到一起后一次性处理,不能按进程编号顺序修改资源状态,否则后面的进程会看到前面进程刚改过的状态:

  1. 若本段有到期的 C 类进程(等待已达 ww),编号最大者抢占资源,其余 C 类申请失败但仍进入运行;
  2. 否则若资源空闲,编号最小的申请者成功;
  3. B 类第 ww 次失败直接进入运行;A 类第 ww 次失败打上“段末释放”标记。
text
段首申请:  收集 requests -> 优先 C 抢夺 -> 空闲则最小号成功 -> 记录 B 放弃 / A 待释放
段中收益:  运行进程 gain += 当前持有资源数, remain--
段末推进:  A 释放全部资源 -> 任务结束则释放并完成 / 否则进入下一任务

死锁检测

没有 C 类进程时系统可能陷入死锁。所有进程开始后,若某个完整系统状态(各进程的阶段、任务、等待时长与资源归属)再次出现,则之后必然无限循环,直接终止并把未完成的进程标为 -1。用哈希集合记录状态即可。

代码

cpp
/**
 * Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
 * rbook: -> https://rbook.roj.ac.cn  https://rbook2.roj.ac.cn
 * rainboy的学习导航网站: https://idx.roj.ac.cn
 * create_at: 2026-07-31 16:22
 * update_at: 2026-08-17 22:40
 */
#include <bits/stdc++.h>
using namespace std;

// 一个进程的全部运行信息
struct Process {
    char type;       // 进程类型 X / A / B / C
    int start_time;  // 开始活动的段首
    int patience;    // 忍耐限度 w
    vector<int> resource; // 每个任务要申请的资源
    vector<int> duration; // 每个任务的持续段数
    int task;        // 当前正在执行第几个任务(从 0 开始)
    int state; // 0: 未开始,1: 申请资源,2: 运行,3: 完成
    int wait_start;  // 本轮等待开始的段首
    int remain;      // 当前任务剩余运行段数
    long long gain;  // 累计收益
    long long finish_time; // 完成时的段号,-1 表示未正常结束
};

vector<Process> process_list; // 1 下标
int owner[41];                // 每种资源当前的占有者,0 表示待使用
bool owns[11][41];            // 进程 i 是否占有资源 j

// 进程 process 抢占资源 resource,把原占有者从该资源上挤掉。
void acquire_resource(int process, int resource) {
    if (owner[resource] != 0) {
        owns[owner[resource]][resource] = false;
    }
    owner[resource] = process;
    owns[process][resource] = true;
}

void release_all(int process) {
    for (int resource = 1; resource <= 40; resource++) {
        if (owns[process][resource]) {
            owns[process][resource] = false;
            owner[resource] = 0;
        }
    }
}

// 计算当前完整系统状态的哈希,用于检测死锁循环。
// 状态包含每个进程的阶段/任务/剩余段数/等待时长以及每种资源的占有者。
unsigned long long state_hash(int current_time, int max_start, int resource_count) {
    unsigned long long result = 1469598103934665603ULL;
    for (int i = 1; i < (int)process_list.size(); i++) {
        Process &process = process_list[i];
        int age = 0;
        if (process.state == 1) {
            age = current_time - process.wait_start;
            if (process.type != 'X') age = min(age, process.patience + 1);
            else age = min(age, 1);
        }
        result ^= (unsigned long long)(process.state + 5 * process.task +
            31 * process.remain + 997 * age + 10007 * i);
        result *= 1099511628211ULL;
    }
    for (int resource = 1; resource <= resource_count; resource++) {
        result ^= (unsigned long long)(owner[resource] + 131 * resource);
        result *= 1099511628211ULL;
    }
    if (current_time <= max_start) result ^= (unsigned long long)current_time;
    return result;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n, resource_count;
    cin >> n >> resource_count;
    process_list.resize(n + 1);
    int max_start = 0;
    for (int i = 1; i <= n; i++) {
        Process &process = process_list[i];
        cin >> process.type;
        int task_count;
        if (process.type == 'X') {
            cin >> process.start_time >> task_count;
            process.patience = 0;
        } else {
            cin >> process.start_time >> process.patience >> task_count;
        }
        max_start = max(max_start, process.start_time);
        process.resource.resize(task_count);
        process.duration.resize(task_count);
        for (int j = 0; j < task_count; j++) {
            cin >> process.resource[j] >> process.duration[j];
        }
        process.task = 0;
        process.state = 0;
        process.wait_start = 0;
        process.remain = 0;
        process.gain = 0;
        process.finish_time = -1;
    }

    memset(owner, 0, sizeof(owner));
    memset(owns, 0, sizeof(owns));
    unordered_set<unsigned long long> visited;
    long long current_time = 1;
    int finished = 0;
    while (finished < n) {
        for (int i = 1; i <= n; i++) {
            if (process_list[i].state == 0 &&
                process_list[i].start_time <= current_time) {
                process_list[i].state = 1;
                process_list[i].wait_start = (int)current_time;
            }
        }

        if (current_time > max_start) {
            unsigned long long hash =
                state_hash((int)current_time, max_start, resource_count);
            if (!visited.insert(hash).second) break;
        }

        // 段首:先收集所有处于申请状态的进程对资源的请求。
        // 同一资源的所有申请必须一起处理,不能按进程编号逐个修改资源状态。
        vector<int> requests[41];
        for (int i = 1; i <= n; i++) {
            if (process_list[i].state == 1) {
                int resource = process_list[i].resource[process_list[i].task];
                requests[resource].push_back(i);
            }
        }

        // release_after 标记段末需要释放全部资源的进程(A 类放弃行为)
        vector<int> release_after(n + 1, 0);
        for (int resource = 1; resource <= resource_count; resource++) {
            if (requests[resource].empty()) continue;
            vector<int> forced;
            for (int j = 0; j < (int)requests[resource].size(); j++) {
                int process_id = requests[resource][j];
                Process &process = process_list[process_id];
                if (process.type == 'C' &&
                    current_time >= process.wait_start + process.patience) {
                    forced.push_back(process_id);
                }
            }

            if (!forced.empty()) {
                int winner = *max_element(forced.begin(), forced.end());
                for (int j = 0; j < (int)forced.size(); j++) {
                    int process_id = forced[j];
                    Process &process = process_list[process_id];
                    if (process_id == winner) acquire_resource(process_id, resource);
                    process.state = 2;
                    process.remain = process.duration[process.task];
                }
                for (int j = 0; j < (int)requests[resource].size(); j++) {
                    int process_id = requests[resource][j];
                    bool is_forced = false;
                    for (int u = 0; u < (int)forced.size(); u++) {
                        if (forced[u] == process_id) is_forced = true;
                    }
                    if (is_forced) continue;
                    Process &process = process_list[process_id];
                    if (process.type == 'B' &&
                        current_time >= process.wait_start + process.patience - 1) {
                        process.state = 2;
                        process.remain = process.duration[process.task];
                    } else if (process.type == 'A' &&
                        current_time >= process.wait_start + process.patience - 1) {
                        release_after[process_id] = 1;
                    }
                }
            } else if (owner[resource] == 0) {
                int winner = *min_element(requests[resource].begin(),
                    requests[resource].end());
                for (int j = 0; j < (int)requests[resource].size(); j++) {
                    int process_id = requests[resource][j];
                    Process &process = process_list[process_id];
                    if (process_id == winner) {
                        acquire_resource(process_id, resource);
                        process.state = 2;
                        process.remain = process.duration[process.task];
                    } else if (process.type == 'B' &&
                        current_time >= process.wait_start + process.patience - 1) {
                        process.state = 2;
                        process.remain = process.duration[process.task];
                    } else if (process.type == 'A' &&
                        current_time >= process.wait_start + process.patience - 1) {
                        release_after[process_id] = 1;
                    }
                }
            } else {
                for (int j = 0; j < (int)requests[resource].size(); j++) {
                    int process_id = requests[resource][j];
                    Process &process = process_list[process_id];
                    if (process.type == 'B' &&
                        current_time >= process.wait_start + process.patience - 1) {
                        process.state = 2;
                        process.remain = process.duration[process.task];
                    } else if (process.type == 'A' &&
                        current_time >= process.wait_start + process.patience - 1) {
                        release_after[process_id] = 1;
                    }
                }
            }
        }

        // 段中:处于运行状态的进程获得等于当前持有资源数的收益,并消耗一段运行时间
        for (int i = 1; i <= n; i++) {
            Process &process = process_list[i];
            if (process.state == 2) {
                int held_count = 0;
                for (int resource = 1; resource <= resource_count; resource++) {
                    if (owns[i][resource]) held_count++;
                }
                process.gain += held_count;
                process.remain--;
            }
        }

        for (int i = 1; i <= n; i++) {
            Process &process = process_list[i];
            if (release_after[i]) {
                release_all(i);
                process.wait_start = (int)current_time + 1;
            }
            if (process.state == 2 && process.remain == 0) {
                process.task++;
                if (process.task == (int)process.resource.size()) {
                    process.state = 3;
                    process.finish_time = current_time;
                    release_all(i);
                    finished++;
                } else {
                    process.state = 1;
                    process.wait_start = (int)current_time + 1;
                }
            }
        }
        current_time++;
    }

    for (int i = 1; i <= n; i++) {
        if (process_list[i].state == 3) {
            cout << process_list[i].gain << ' '
                 << process_list[i].finish_time - process_list[i].start_time + 1 << '\n';
        } else {
            cout << process_list[i].gain << " -1\n";
        }
    }
    return 0;
}

复杂度

  • 时间:每段需要 O(nm)O(nm) 处理请求与统计收益,本题 n10, m40n\le 10,\ m\le 40,模拟段数有界。
  • 空间:O(nm)O(nm),加上死锁检测使用的哈希集合。

总结

资源申请必须按段首的同时性统一处理,不能按进程编号依次修改资源状态;把每一段拆成“申请、收益、推进”三个阶段即可准确模拟特殊规则。死锁检测的关键是识别出完整系统状态的循环。