为何tee命令会改变命名管道(named fifo)的运行行为?
命名管道双向通信挂起问题分析
场景与现象
我用基于随机数和BSGS算法实现的C++代码(已通过Codeforces 1840G2测试),与Python判题程序通过命名管道做双向通信调试时遇到如下问题:
操作步骤
- 准备工作:
- 将下方Python判题代码保存为
gen.py - 编译C++代码为可执行文件
g2.exe - 在工作目录创建两个命名管道:
makefifo g2in; makefifo g2out;
- 将下方Python判题代码保存为
- 异常执行:打开两个终端分别运行
和./g2 < g2in > g2out
结果是两个终端永久挂起,无任何进展。./gen.py < g2out > g2in - 正常执行:修改其中一条命令为
另一条命令不变,程序能正常运行并退出,判题程序也能正确识别结果。./g2 < g2in | tee g2out
我已获取两种情况的strace日志,希望了解挂起的原因以及加入tee后的差异。
Python判题代码
#!/usr/bin/env python import sys import random import subprocess def main(): n = random.randint(1, 10**6) sys.stderr.write(f"begin with {n=}\n") v = [x + 1 for x in range(n)] random.shuffle(v) idx = 0 opt = 0 print(f"{v[idx]}") sys.stdout.flush() while True: line = input() if not line: break if line[0] == '!': exp = int(line[1:]) if exp == n: sys.stderr.write(f"get right ans {exp=}\n") return 0 else: raise Exception(f"real {n=}, {exp=}\n") else: op = line[0] cnt = int(line[1:]) sys.stderr.write(f"get a query request at {cnt=}\n") if op == '+': idx = (idx + cnt) % n else: assert op == '-', f"{op} not '-'" idx = (idx - cnt) % n print(f"{v[idx]}") sys.stdout.flush() sys.stderr.write(f"write and flush ans {v[idx]=} done\n") opt += 1 if opt % 100 == 0: sys.stderr.write(f"opt get ${opt}\n") if opt >= 1000: break raise Exception("Too many try") if __name__ == "__main__": main()
已AC的C++代码
#include <assert.h> #include <bits/stdc++.h> using namespace std; #ifdef __DEBUG__ #include "dbg.h" #else #define dbg(...) 42 #endif template <class T> using mpq = priority_queue<T, vector<T>, greater<T>>; using ll = long long; using pii = pair<int, int>; using pll = pair<ll, ll>; using vl = vector<ll>; using vi = vector<int>; mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); int get_rdn() { return rng() % int(1e6 + 3); } int main(int argc, char **argv) { int x, m = 0; scanf("%d", &m); dbg(m); for (int i = 0; i < 300; ++i) { int roll = get_rdn(); printf("+ %d\n", roll), fflush(stdout); scanf("%d", &x); m = max(m, x); } dbg(m); map<int, int> cnt; int offset = 0; for (int i = 0; i < 340; ++i) { printf("+ 1\n"), fflush(stdout); scanf("%d", &x); if (cnt.count(x)) { printf("! %d\n", offset), fflush(stdout); return 0; } cnt[x] = offset++; } dbg(offset); printf("+ %d\n", m - 340), fflush(stdout); scanf("%d", &x); offset = 0; for (int i = 0; i < 340; ++i) { printf("+ 340\n"), fflush(stdout); scanf("%d", &x); if (cnt.count(x)) { dbg(offset + m + 339 - cnt[x]); printf("! %d\n", offset + m + 339 - cnt[x]), fflush(stdout); return 0; } offset += 340; } return 0; };
运行环境
WSL2(Linux Ubuntu-WSL2 4.19.128-microsoft-standard #1 SMP Tue Jun 23 12:58:10 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux)
内容的提问来源于stack exchange,提问作者Liu Weibo
相关产品推荐
相关产品推荐

