【发布时间】:2012-10-26 05:33:46
【问题描述】:
我正在编写一个与外部进程交互的 C++ 程序。外部进程用 C# 编写并在单声道上运行。请注意,我无法修改 C# 代码,因为它不是我编写的程序。
在这方面,我首先使用管道,当然后来我意识到它是完全缓冲的,因此我遇到了很多同步问题。本质上,外部进程必须在每次写入后刷新其输出,这是不可能的。
接下来我要尝试的是文件,但是我发现在我的情况下使用伪终端更合适。这是我编写的一些示例代码:
int main()
{
int fdm, fds, rc, pid;
bool rValue;
/* Setup Master pty*/
rValue = rValue && (fdm = posix_openpt(O_RDWR)) >= 0 &&
(rc = grantpt(fdm)) == 0 && (rc = unlockpt(fdm) == 0);
if (rValue) {
/* Open Slave pty */
fds = open(ptsname(fdm), O_RDWR);
pid = fork();
if(pid < 0)
perror("fork failed");
else if(pid == 0) //child
{
close(fdm); //close master
struct termios slave_orig_term_settings;
struct termios new_term_settings;
tcgetattr(slaveTTY, &slave_orig_term_settings);
new_term_settings = slave_orig_term_settings;
cfmakeraw(&new_term_settings);
tcsetattr(slaveTTY, TCSANOW, &new_term_settings);
//redirect I/O of this process
close(0);
close(1);
close(2);
dup(slaveTTY);
dup(slaveTTY);
dup(slaveTTY);
close(slaveTTY);
setsid();
ioctl(0, TIOCSCTTY, 1);
//launch the external process and replace its image in this process
execve(argv[0],...);
}
else
{
close(fds); //close slave
//Perform some interaction
write(something using fdm);
//Assume fdsets declared and set somewhere here
select(fdm +1,&fdset,NULL,NULL,NULL);
int readBytes = read(someting using fds);
}
}
return EXIT_SUCCESS;
}
假设 fdset 和 fdclr for select 正在处理中。
在父进程中观察到以下问题:
- 有时读取返回时 readBytes > 0 但缓冲区中没有任何内容
- 有时写入终端的任何内容都会被回读
- 一些垃圾值,例如 ^]]49]1R 被转储到终端(这是实际终端,即我的输出窗口)
P.S:当外部进程用 C/C++ 编写时,不会出现此问题。仅当我以单声道运行 C# 程序时。
【问题讨论】:
-
只是为了澄清,来自
pipe(2)manual page:“写入管道写入端的数据由内核缓冲,直到从管道的读取端读取。”这意味着管道本身没有“完全缓冲”,但很可能与您通信的程序将其输出单独缓冲,例如从 C 程序写入stdout。 -
@JoachimPileborg 同意你的说法。事实上,这正是程序正在做的事情。