You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何tee命令会改变命名管道(named fifo)的运行行为?

命名管道双向通信挂起问题分析

场景与现象

我用基于随机数和BSGS算法实现的C++代码(已通过Codeforces 1840G2测试),与Python判题程序通过命名管道做双向通信调试时遇到如下问题:

操作步骤

  1. 准备工作:
    • 将下方Python判题代码保存为gen.py
    • 编译C++代码为可执行文件g2.exe
    • 在工作目录创建两个命名管道:makefifo g2in; makefifo g2out;
  2. 异常执行:打开两个终端分别运行
    ./g2 < g2in > g2out
    
    和
    ./gen.py < g2out > g2in
    
    结果是两个终端永久挂起,无任何进展。
  3. 正常执行:修改其中一条命令为
    ./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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 16:45:02