Nó không chỉ có thể được thực hiện, nó có thể được thực hiện mà không có gì ngoài một tệp bó! :-)
Vấn đề có thể được giải quyết bằng cách sử dụng tệp tạm thời làm "đường ống". Giao tiếp hai chiều yêu cầu hai tệp "ống".
Quá trình A đọc stdin từ "pipe1" và ghi stdout vào "pipe2"
Process B đọc stdin từ "pipe2" và ghi stdout vào "pipe1"
Điều quan trọng là cả hai tệp tồn tại trước khi khởi chạy một trong hai quá trình. Các tập tin nên trống khi bắt đầu.
Nếu một tệp bó cố gắng đọc từ một tệp xảy ra ở cuối hiện tại, nó chỉ đơn giản trả về không có gì và tệp vẫn mở. Vì vậy, thói quen readLine của tôi liên tục đọc cho đến khi nó nhận được một giá trị không trống.
Tôi muốn có thể đọc và viết một chuỗi trống, vì vậy thói quen writeLine của tôi sẽ thêm một ký tự phụ mà readLine loại bỏ.
Quá trình A của tôi kiểm soát dòng chảy. Nó khởi tạo mọi thứ bằng cách viết 1 (tin nhắn cho B), sau đó vào một vòng lặp với 10 lần lặp trong đó nó đọc một giá trị (tin nhắn từ B), thêm 1, sau đó viết kết quả (tin nhắn cho B). Cuối cùng, nó chờ tin nhắn cuối cùng từ B, rồi viết tin nhắn "thoát" cho B và thoát ra.
Quá trình B của tôi nằm trong một vòng lặp vô điều kiện có thể đọc một giá trị (tin nhắn từ A), thêm 10 và sau đó ghi kết quả (tin nhắn cho A). Nếu B từng đọc tin nhắn "thoát" thì nó sẽ chấm dứt ngay lập tức.
Tôi muốn chứng minh rằng giao tiếp hoàn toàn đồng bộ, vì vậy tôi đưa ra độ trễ trong cả hai vòng xử lý A và B.
Lưu ý rằng thủ tục readLine nằm trong một vòng lặp chặt chẽ liên tục lạm dụng cả CPU và hệ thống tệp trong khi nó chờ đầu vào. Một độ trễ PING có thể được thêm vào vòng lặp, nhưng sau đó các quy trình sẽ không được đáp ứng.
Tôi sử dụng một đường ống thực sự như một sự thuận tiện để khởi chạy cả hai quá trình A và B. Nhưng đường ống là không hoạt động trong đó không có giao tiếp đi qua nó. Tất cả thông tin liên lạc là thông qua các tập tin "ống" tạm thời của tôi.
Tôi cũng có thể đã sử dụng START / B để khởi chạy các tiến trình, nhưng sau đó tôi phải phát hiện khi cả hai chấm dứt để tôi biết khi nào nên xóa các tệp "ống" tạm thời. Nó đơn giản hơn nhiều để sử dụng đường ống.
Tôi đã chọn đặt tất cả mã vào một tệp duy nhất - tập lệnh chính khởi chạy A và B, cũng như mã cho A và B. Tôi có thể đã sử dụng một tệp tập lệnh riêng cho mỗi quy trình.
kiểm tra
@echo off
if "%~1" equ "" (
copy nul pipe1.txt >nul
copy nul pipe2.txt >nul
"%~f0" A <pipe1.txt >>pipe2.txt | "%~f0" B <pipe2.txt >>pipe1.txt
del pipe1.txt pipe2.txt
exit /b
)
setlocal enableDelayedExpansion
set "prog=%~1"
goto !prog!
:A
call :writeLine 1
for /l %%N in (1 1 5) do (
call :readLine
set /a ln+=1
call :delay 1
call :writeLine !ln!
)
call :readLine
call :delay 1
call :writeLine quit
exit /b
:B
call :readLine
if !ln! equ quit exit /b
call :delay 1
set /a ln+=10
call :writeLine !ln!
goto :B
:readLine
set "ln="
set /p "ln="
if not defined ln goto :readLine
set "ln=!ln:~0,-1!"
>&2 echo !prog! reads !ln!
exit /b
:writeLine
>&2 echo !prog! writes %*
echo(%*.
exit /b
:delay
setlocal
set /a cnt=%1+1
ping localhost /n %cnt% >nul
exit /b
--OUTPUT--
C:\test>test
A writes 1
B reads 1
B writes 11
A reads 11
A writes 12
B reads 12
B writes 22
A reads 22
A writes 23
B reads 23
B writes 33
A reads 33
A writes 34
B reads 34
B writes 44
A reads 44
A writes 45
B reads 45
B writes 55
A reads 55
A writes 56
B reads 56
B writes 66
A reads 66
A writes quit
B reads quit
Cuộc sống dễ dàng hơn một chút với ngôn ngữ cấp cao hơn. Dưới đây là một ví dụ sử dụng VBScript cho các quy trình A và B. Tôi vẫn sử dụng hàng loạt để khởi chạy các quy trình. Tôi sử dụng một phương pháp rất hay được mô tả tại Có thể nhúng và thực thi VBScript trong một tệp bó mà không cần sử dụng tệp tạm thời không? để nhúng nhiều tập lệnh VBS trong một tập lệnh bó.
Với ngôn ngữ cao hơn như VBS, chúng tôi có thể sử dụng một đường ống bình thường để truyền thông tin từ A đến B. Chúng tôi chỉ cần một tệp "ống" tạm thời duy nhất để chuyển thông tin từ B trở lại A. Bởi vì bây giờ chúng tôi có một ống hoạt động, A quá trình không cần gửi tin nhắn "thoát" đến B. Quá trình B chỉ đơn giản là vòng lặp cho đến khi đến cuối tập tin.
Nó chắc chắn là tốt đẹp khi có quyền truy cập vào một chức năng ngủ thích hợp trong VBS. Điều này cho phép tôi dễ dàng giới thiệu một độ trễ ngắn trong chức năng readLine để cho CPU nghỉ ngơi.
Tuy nhiên, có một nếp nhăn trong readLIne. Lúc đầu, tôi nhận được những thất bại không liên tục cho đến khi tôi nhận ra rằng đôi khi readLine sẽ phát hiện thông tin có sẵn trên stdin và ngay lập tức sẽ cố gắng đọc dòng trước khi B có cơ hội viết xong dòng này. Tôi đã giải quyết vấn đề bằng cách đưa ra một độ trễ ngắn giữa bài kiểm tra cuối tập tin và bài đọc. Một sự chậm trễ 5 ms dường như là một mánh khóe đối với tôi, nhưng tôi đã nhân đôi con số đó lên 10 ms chỉ để ở bên an toàn. Điều rất thú vị là lô không bị vấn đề này. Chúng tôi đã thảo luận ngắn gọn về điều này (5 bài viết ngắn) tại http://www.dostips.com/forum/viewtopic.php?f=3&t=7078#p47432 .
<!-- : Begin batch script
@echo off
copy nul pipe.txt >nul
cscript //nologo "%~f0?.wsf" //job:A <pipe.txt | cscript //nologo "%~f0?.wsf" //job:B >>pipe.txt
del pipe.txt
exit /b
----- Begin wsf script --->
<package>
<job id="A"><script language="VBS">
dim ln, n, i
writeLine 1
for i=1 to 5
ln = readLine
WScript.Sleep 1000
writeLine CInt(ln)+1
next
ln = readLine
function readLine
do
if not WScript.stdin.AtEndOfStream then
WScript.Sleep 10 ' Pause a bit to let B finish writing the line
readLine = WScript.stdin.ReadLine
WScript.stderr.WriteLine "A reads " & readLine
exit function
end if
WScript.Sleep 10 ' This pause is to give the CPU a break
loop
end function
sub writeLine( msg )
WScript.stderr.WriteLine "A writes " & msg
WScript.stdout.WriteLine msg
end sub
</script></job>
<job id="B"> <script language="VBS">
dim ln, n
do while not WScript.stdin.AtEndOfStream
ln = WScript.stdin.ReadLine
WScript.stderr.WriteLine "B reads " & ln
n = CInt(ln)+10
WScript.Sleep 1000
WScript.stderr.WriteLine "B writes " & n
WScript.stdout.WriteLine n
loop
</script></job>
</package>
Đầu ra giống như với giải pháp lô thuần túy, ngoại trừ dòng "thoát" cuối cùng không có ở đó.