news 2026/10/28 1:37:10

UVa 611 Parallel Deadlock

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
UVa 611 Parallel Deadlock

题目描述

并行计算中,处理器间通过发送(S)和接收(R)消息进行通信。每条指令可以是阻塞(B)或非阻塞(N)模式。阻塞发送要求目标处理器执行匹配的接收才能完成,阻塞接收要求源处理器执行匹配的发送才能完成;非阻塞操作立即返回,但真正完成仍需匹配操作。消息按发送顺序接收,并在匹配双方均执行对应操作后,在当前时间步结束时完成。一个正确的程序在所有操作(包括非阻塞操作)完成后终止。

给定若干处理器及其指令序列,需要模拟执行过程,判断每个处理器是否能在有限时间内完成其全部指令,若不能,则找出阻止其完成的处理器集合。

输入格式

第一行是数据集个数TTT,随后一个空行。每个数据集第一行为正整数PPP,表示处理器个数。接下来PPP个处理器,每个先占一行,包含处理器名称(单个大写字母)和指令条数MMM,随后MMM行指令。每条指令格式为Mode Action Target(s),其中Mode为B或N,Action为S或R,Target(s)为若干目标处理器名称(单个大写字母)。处理器不会与自己通信,且目标不重复。

输出格式

对于每个数据集,按处理器名称字母顺序输出。若处理器完成,输出X finishes at t=T;若未完成,输出X never finishes because of Y and Z,其中Y、Z等为阻止该处理器完成的处理器名称,按字母顺序排列,多个之间用and连接。每个数据集输出后(除最后一个)空一行。

样例

输入

1 4 I 5 B S B P C N S B P C N R B B R P B R C B 2 B R I B S I P 3 N S I N R I B R I C 4 N S I B R I B S P B R I

输出

B finishes at t=4 C never finishes because of P I never finishes because of B and C P finishes at t=5

题目分析

本题要求模拟并行执行过程,核心挑战在于:

  1. 阻塞与非阻塞:阻塞指令会挂起处理器,直到匹配完成;非阻塞指令立即前进,但其未完成操作仍会阻塞程序终止。
  2. 多目标通信:一条发送或接收指令可指定多个目标,必须等待所有目标的匹配操作完成,该指令才算完成。
  3. 死锁检测:当所有未完成处理器都因等待对方而停滞,且没有新的匹配可能发生时,程序进入死锁。

直接枚举时间步模拟是自然的思路。每个时间步分为“执行”和“匹配”两个阶段。执行阶段让所有未阻塞且未完成的处理器执行下一条指令,生成对应的通信请求;匹配阶段则尝试配对同时存在的发送与接收请求。若某时间步没有执行任何新指令也没有任何匹配发生,则系统死锁。

还需注意,非阻塞操作即使立即返回,其父操作仍需收集所有目标的匹配,因此也需要维护其完成状态。

解题思路

数据结构设计

  • 处理器信息:Processor结构体包含名称、指令列表、程序计数器ip、是否阻塞blocked、未完成的父操作列表pendingOps(存储父操作ID\texttt{ID}ID)、是否完成finished、完成时间finishTime。
  • 指令:Instruction记录模式、动作、目标列表(字符数组)。
  • 父操作:ParentOp记录所属处理器索引、指令索引、模式、动作、目标列表、每个目标是否已匹配(matchedTargets布尔数组)、已匹配数、所需匹配数、是否完成。每个处理器执行一条指令即产生一个父操作。
  • 子操作队列:对于每一对方向(src, dst),分别维护发送队列sendQ[src][dst]和接收队列recvQ[src][dst],队列元素为SubOp,包含父操作ID\texttt{ID}ID和该子操作的目标处理器。当处理器执行发送指令时,为每个目标向sendQ[src][dst]添加一个子操作;执行接收指令时,为每个源处理器向recvQ[src][dst]添加子操作。

模拟过程

  1. 初始化:读取所有处理器及其指令,建立名称到索引的映射。
  2. 时间步循环(t从111开始递增):
    • 执行阶段:遍历所有未完成、未阻塞且程序未结束的处理器。
      • 创建ParentOp,将其ID\texttt{ID}ID加入处理器的pendingOps。
      • 根据动作(S或R)和目标列表,向对应的sendQ或recvQ添加子操作。
      • 若指令为阻塞,置blocked = true;否则ip++。
    • 匹配阶段:遍历所有26×2626×2626×26个方向。若发送队列和接收队列均非空,则分别取出队首子操作并配对。
      • 对于发送子操作,其目标为dst;接收子操作的目标为src。
      • 调用辅助函数finishParent(parentId, target):在父操作的目标列表中标记该target为已匹配;若所有目标均已匹配,则标记父操作完成,从所属处理器的pendingOps中移除,若该处理器正阻塞在该指令上,则解除阻塞并ip++。
    • 完成检查:遍历所有处理器,若其ip等于指令总数且pendingOps为空,则标记为完成,记录当前时间步t。
    • 终止判断:若所有处理器均完成,则退出循环;若本时间步既没有执行新指令也没有发生任何匹配,则判定为死锁,退出循环。
  3. 输出:按字母顺序排序处理器。已完成者输出完成时间;未完成者收集其所有未完成父操作中尚未匹配的目标处理器(即matchedTargets为false的目标),去重后按字母顺序输出。

正确性说明

  • 每个时间步的执行顺序不影响匹配的正确性,因为所有新生成的请求在同一时间步内均可参与匹配(消息可在发送时间步结束时被接收)。
  • 阻塞指令的解除发生在匹配完成后,因此解除后的处理器能在下一时间步执行新指令。
  • 死锁检测条件“无执行且无匹配”成立时,系统确实不可能再产生任何新的通信请求或完成已有匹配,因此程序将永远停滞。

复杂度分析

设处理器数为PPP(P≤26P \le 26P≤26),每个处理器指令数不超过100100100,总指令数为O(100P)O(100P)O(100P)。每个指令的目标数最多为PPP,因此总通信子操作数为O(100P2)O(100P^2)O(100P2)。时间步数受限于总操作数和死锁检测,实际模拟过程中每个处理器最多执行100100100条指令,且每次匹配至少完成一个子操作,因此时间步数不超过O(100P2)O(100P^2)O(100P2)。每一时间步遍历PPP个处理器和26226^2262个方向,故总时间复杂度为O(100P2⋅(P+262))O(100P^2 \cdot (P + 26^2))O(100P2⋅(P+262)),在给定范围(P≤26P \le 26P≤26)下可接受。空间复杂度为O(100P2)O(100P^2)O(100P2),用于存储父操作和子操作队列。

代码实现

// Parallel Deadlock// UVa ID: 611// Verdict: Accepted// Submission Date: 2026-07-05// UVa Run Time: 0.000s//// 版权所有(C)2026,邱秋。metaphysis # yeah dot net#include<bits/stdc++.h>usingnamespacestd;structInstruction{charmode,action;vector<char>targets;};structProcessor{charname;vector<Instruction>prog;intip;boolblocked;vector<int>pendingOps;boolfinished;intfinishTime;};structParentOp{intprocIdx,instIdx;charmode,action;vector<char>targets;vector<bool>matchedTargets;intmatchedCount,requiredCount;boolcompleted;};structSubOp{intparentId;chartargetChar;};intmain(){intdatasetCnt;string line;cin>>datasetCnt;getline(cin,line);for(intds=0;ds<datasetCnt;++ds){while(getline(cin,line)&&line.empty());intK=stoi(line);vector<Processor>procs;unordered_map<char,int>nameIdx;vector<ParentOp>parentOps;queue<SubOp>sendQ[26][26],recvQ[26][26];for(inti=0;i<K;++i){while(getline(cin,line)&&line.empty());istringstreamiss(line);charname;intn;iss>>name>>n;Processor p;p.name=name;p.ip=0;p.blocked=false;p.finished=false;p.finishTime=0;for(intj=0;j<n;++j){while(getline(cin,line)&&line.empty());istringstreamiss2(line);string modeStr,actionStr;iss2>>modeStr>>actionStr;Instruction inst;inst.mode=modeStr[0];inst.action=actionStr[0];chartarget;while(iss2>>target)inst.targets.push_back(target);p.prog.push_back(inst);}procs.push_back(p);nameIdx[name]=i;}intt=0;while(true){boolhasExecuted=false,hasMatched=false;++t;// 执行阶段for(inti=0;i<(int)procs.size();++i){Processor&p=procs[i];if(p.finished||p.blocked||p.ip>=(int)p.prog.size())continue;hasExecuted=true;Instruction&inst=p.prog[p.ip];ParentOp op;op.procIdx=i;op.instIdx=p.ip;op.mode=inst.mode;op.action=inst.action;op.targets=inst.targets;op.matchedTargets.assign(inst.targets.size(),false);op.matchedCount=0;op.requiredCount=(int)inst.targets.size();op.completed=false;intparentId=(int)parentOps.size();parentOps.push_back(op);p.pendingOps.push_back(parentId);for(chartarget:inst.targets){SubOp sub;sub.parentId=parentId;sub.targetChar=target;if(inst.action=='S'){sendQ[p.name-'A'][target-'A'].push(sub);}else{recvQ[target-'A'][p.name-'A'].push(sub);}}if(inst.mode=='B')p.blocked=true;elsep.ip++;}// 匹配阶段autofinishParent=[&](intpid,chartarget){ParentOp&op=parentOps[pid];for(intidx=0;idx<(int)op.targets.size();++idx)if(op.targets[idx]==target&&!op.matchedTargets[idx]){op.matchedTargets[idx]=true;op.matchedCount++;if(op.matchedCount!=op.requiredCount||op.completed)return;op.completed=true;Processor&p=procs[op.procIdx];auto&pend=p.pendingOps;pend.erase(remove(pend.begin(),pend.end(),pid),pend.end());if(op.mode=='B'&&p.blocked&&p.ip==op.instIdx){p.blocked=false;p.ip++;}break;}};for(intsrc=0;src<26;++src){for(intdst=0;dst<26;++dst){if(sendQ[src][dst].empty()||recvQ[src][dst].empty())continue;SubOp sendSub=sendQ[src][dst].front();sendQ[src][dst].pop();SubOp recvSub=recvQ[src][dst].front();recvQ[src][dst].pop();hasMatched=true;finishParent(sendSub.parentId,(char)('A'+dst));finishParent(recvSub.parentId,(char)('A'+src));}}// 检查完成for(inti=0;i<(int)procs.size();++i){Processor&p=procs[i];if(!p.finished&&p.ip==(int)p.prog.size()&&p.pendingOps.empty()){p.finished=true;p.finishTime=t;}}boolallDone=true;for(auto&p:procs)if(!p.finished){allDone=false;break;}if(allDone)break;if(!hasExecuted&&!hasMatched)break;}sort(procs.begin(),procs.end(),[](constProcessor&a,constProcessor&b){returna.name<b.name;});for(auto&p:procs){if(p.finished){cout<<p.name<<" finishes at t="<<p.finishTime<<"\n";}else{set<char>blockers;for(intpid:p.pendingOps){ParentOp&op=parentOps[pid];if(op.completed)continue;for(intidx=0;idx<(int)op.targets.size();++idx)if(!op.matchedTargets[idx])blockers.insert(op.targets[idx]);}cout<<p.name<<" never finishes because of ";vector<char>vec(blockers.begin(),blockers.end());for(inti=0;i<(int)vec.size();++i){if(i>0)cout<<" and ";cout<<vec[i];}cout<<"\n";}}if(ds!=datasetCnt-1)cout<<"\n";}return0;}

总结

本题通过逐时间步模拟并行通信过程,并结合队列匹配机制,正确处理了阻塞/非阻塞、多目标通信和死锁检测。关键点在于:

  • 将每条指令视为一个父操作,其多个目标子操作分别入队,利用队列保证消息顺序。
  • 匹配阶段遍历所有方向,仅当双方队列均非空时才配对,避免遗漏。
  • 死锁检测条件简单有效:无新执行且无匹配。
  • 阻止者收集需排除已匹配目标,仅统计尚未匹配的目标处理器。

该解法在题目给定约束下运行高效,代码结构清晰,适合作为并行死锁模拟的参考实现。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/28 1:36:12

BEMD图像分解实战:MATLAB实现原理与参数调优指南

简介&#xff1a;这是一份基于MATLAB实现的二维经验模态分解&#xff08;BEMD&#xff09;算法资源包&#xff0c;面向数值算法与人工智能领域的研究者、工程师及高校师生&#xff0c;适用于非线性、非平稳信号及多变量耦合数据的分析与处理&#xff0c;在环境、金融、生物医学…

作者头像 李华
网站建设 2026/10/28 1:35:39

车牌识别系统实战:从畸变校正到端到端OCR部署

简介&#xff1a;本资源是一套完整的基于Python与OpenCV实现的车牌识别系统毕业设计项目&#xff0c;面向计算机视觉初学者、深度学习实践者及本科毕设学生&#xff0c;解决真实场景下车牌图像定位与字符识别两大核心问题。系统采用双CNN架构&#xff1a;前段负责车牌区域定位&…

作者头像 李华
网站建设 2026/10/28 1:34:36

@Transactional事务问题

文章目录前言一、try/catch 里把异常“吃掉了&#xff0c;事务不会回滚二、方法抛出 Checked Exception 且未配置 rollbackFor&#xff0c;事务不会回滚三&#xff1a;Transactional 在同类方法调用会失效四&#xff1a;private 方法导致事务失效总结前言 Spring事务默认只对 …

作者头像 李华
网站建设 2026/10/28 1:32:30

c++进阶之多态

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/28 1:32:07

2000-2024年 地级市-城乡居民社保相关数据数据(xlsx)

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华