2015-02-04 3 views
7

क्या बंद करने के लिए कोई तरीका है कि एक पाठक ने नामित पाइप (या बाहर निकला), के के बिना इसे बंद कर दिया है?पता लगाएं कि पाठक नामित पाइप (एफआईएफओ)

मुझे यह जानने की ज़रूरत है क्योंकि पाइप को लिखने वाला प्रारंभिक डेटा अलग है; शेष डेटा आने से पहले पाठक प्रारंभिक शीर्षलेख की अपेक्षा कर रहा है।

वर्तमान में, मुझे यह पता चलता है जब मेरा write()EPIPE के साथ विफल रहता है। फिर मैंने एक ध्वज सेट किया जो कहता है "अगली बार, हेडर भेजें"। हालांकि, कुछ भी लिखने से पहले पाठक को बंद करने और पाइप को फिर से खोलना संभव है। इस मामले में, मुझे कभी नहीं पता कि उसने क्या किया है, और वह जिस हेडर की अपेक्षा कर रहा है उसे न भेजें।

क्या एसिंक घटना प्रकार की कोई चीज है जो यहां मदद कर सकती है? मुझे कोई सिग्नल भेजा नहीं जा रहा है।

ध्यान दें कि मैंने कोई भी भाषा टैग शामिल नहीं किया है, क्योंकि इस प्रश्न को भाषा-अज्ञेयवादी माना जाना चाहिए। मेरा कोड पायथन है, लेकिन उत्तर सी, या सिस्टम कॉल-स्तरीय बाइंडिंग के साथ किसी भी अन्य भाषा पर लागू होना चाहिए।

+0

मैन 2 लिखें: 'EPIPE' 'fd एक पाइप या सॉकेट से जुड़ा हुआ है जिसका पढ़ने का अंत बंद है। जब ऐसा होता है तो लेखन प्रक्रिया को एक SIG- पीआईपीई सिग्नल भी प्राप्त होगा।(इस प्रकार, लिखने का वापसी मूल्य केवल तभी देखा जाता है जब प्रोग्राम इस सिग्नल को पकड़ता है, ब्लॉक करता है या अनदेखा करता है।) – wildplasser

+0

कोई कारण नहीं है कि समय-समय पर हेडर डेटा न भेजें? अगर पाठक उनके साथ सौदा कर सकता है, तो शायद यह अनावश्यक हेडर से निपट सकता है? – wallyk

+0

@ विल्डप्लेसर मुझे यकीन नहीं है कि आप अभी क्या बिंदु बना रहे हैं। हां, मुझे पता है कि जब मैं इसे लिखने की कोशिश करता हूं तो पाइप बंद हो जाती है। मेरा सवाल यह पूछ रहा है कि लिखने के बिना अतुल्यकालिक रूप से इसका पता कैसे लगाया जाए। –

उत्तर

2

अजीब तरह से पर्याप्त है, यह प्रकट होता है जब पिछले पाठक पाइप बंद कर देता है, select इंगित करता है कि पाइप पढ़ी जा सकती है:

writer.py

#!/usr/bin/env python 
import os 
import select 
import time 

NAME = 'fifo2' 

os.mkfifo(NAME) 


def select_test(fd, r=True, w=True, x=True): 
    rset = [fd] if r else [] 
    wset = [fd] if w else [] 
    xset = [fd] if x else [] 

    t0 = time.time() 
    r,w,x = select.select(rset, wset, xset) 

    print 'After {0} sec:'.format(time.time() - t0) 
    if fd in r: print ' {0} is readable'.format(fd) 
    if fd in w: print ' {0} is writable'.format(fd) 
    if fd in x: print ' {0} is exceptional'.format(fd) 

try: 
    fd = os.open(NAME, os.O_WRONLY) 
    print '{0} opened for writing'.format(NAME) 

    print 'select 1' 
    select_test(fd) 

    os.write(fd, 'test') 
    print 'wrote data' 

    print 'select 2' 
    select_test(fd) 

    print 'select 3 (no write)' 
    select_test(fd, w=False) 

finally: 
    os.unlink(NAME) 

डेमो:

टर्मिनल 1:

$ ./pipe_example_simple.py 
fifo2 opened for writing 
select 1 
After 1.59740447998e-05 sec: 
3 is writable 
wrote data 
select 2 
After 2.86102294922e-06 sec: 
3 is writable 
select 3 (no write) 
After 2.15910816193 sec: 
3 is readable 

टर्मिनल 2:

$ cat fifo2 
test 
# (wait a sec, then Ctrl+C) 
3

आप एक घटना पाश कि poll प्रणाली पर आधारित है प्रयोग कर रहे हैं फोन आप एक घटना मुखौटा कि EPOLLERR शामिल साथ पाइप रजिस्टर कर सकते हैं। अजगर, select.poll साथ, में

import select 
fd = open("pipe", "w") 
poller = select.poll() 
poller.register(fd, select.POLLERR) 
poller.poll() 

जब तक पाइप बंद कर दिया है इंतजार करेंगे।

इसका परीक्षण करने के लिए, mkfifo pipe चलाएं, स्क्रिप्ट शुरू करें, और दूसरे टर्मिनल रन में, उदाहरण के लिए, cat pipe। जैसे ही आप cat प्रक्रिया को छोड़ देते हैं, स्क्रिप्ट समाप्त हो जाएगी।

+0

यहां 'परादाता' क्या है? –

+0

सोरी, मैं उस पंक्ति को जोड़ना भूल गया। यह एक 'select.poll' ऑब्जेक्ट है। – Phillip

+0

दूसरा तर्क 'select.POLLERR' होना चाहिए, न कि' select.EPOLLERR'। इसके अलावा, क्या आपने वास्तव में यह कोशिश की है? 'चयन' ([नीचे] (http://stackoverflow.com/a/28472725/119527) के साथ मेरा परीक्षण इंगित करता है कि पाइप आश्चर्यजनक रूप से * पठनीय *, * असाधारण * नहीं बनता है जब दूसरा अंत बंद हो जाता है। –

1

ऐसी कोई प्रक्रिया नहीं है। आम तौर पर, यूनिक्स-मार्ग के अनुसार, किसी भी अंत में, खोलने या बंद करने वाली धाराओं के लिए कोई सिग्नल नहीं होता है। यह केवल उन्हें पढ़ने या लिखने के द्वारा ही पता लगाया जा सकता है (तदनुसार)।

मैं कहूंगा कि यह गलत डिज़ाइन है। वर्तमान में आप रिसीवर को पाइप खोलकर अपनी उपलब्धता को प्राप्त करने की कोशिश कर रहे हैं। तो या तो आप इस सिग्नलिंग को उचित तरीके से कार्यान्वित करते हैं, या पाइप के भेजने वाले भाग में "समापन तर्क" शामिल करते हैं।

+0

'" ऐसी कोई व्यवस्था नहीं है। "क्या आपने ऊपर अपना जवाब देखा, जो स्पष्ट रूप से इंगित करता है कि आप गलत हैं? –

+0

'मतदान' और 'चयन' कॉल का उपयोग यह पता लगाने के लिए किया जाता है कि जब कोई एफडी पढ़ने/लिखने के लिए तैयार होता है, तो अवरुद्ध होने से बचने के लिए। स्ट्रीमिंग ओपनिंग या क्लोजिंग पर अभी भी कोई सिग्नलिंग जानकारी नहीं है, और इसे पहचानने के लिए आपको पढ़ने/लिखने की तैयारी के लिए पढ़ने/लिखने या _test_ करने की आवश्यकता होगी। मैं मानता हूं कि यह जानकारी छोड़ी गई है। उत्तर बदलता नहीं है, फिर भी, क्योंकि मतदान अभी भी एक सिग्नलिंग तंत्र नहीं है, और आपके द्वारा वर्णित दौड़ की स्थितियों (मतदान/पढ़ने/लिखने से पहले पाइप बंद करना और फिर से खोलना) अभी भी 'मतदान' के साथ है। इसे मतदान करने से पहले इसे फिर से खोल दिया जा सकता है। –

संबंधित मुद्दे