2012-03-26 15 views
8

क्या यह एक ही समय में एक ही फ़ाइल में एकाधिक प्रक्रियाओं को लिखने (लिखने) के लिए ठीक है? निम्नलिखित कोड का उपयोग करना, ऐसा लगता है, लेकिन मुझे संदेह है।एक ही फ़ाइल को एक्सेस करने वाली एकाधिक प्रक्रिया

उदाहरण में केस का उपयोग एक निष्पादन योग्य है जिसे ईमेल प्राप्त होने पर हर बार बुलाया जाता है और इसे केंद्रीय फ़ाइल में आउटपुट लॉग करता है।

if (freopen(console_logfile, "a+", stdout) == NULL || freopen(error_logfile, "a+", stderr) == NULL) { 
    perror("freopen"); 
} 
printf("Hello World!"); 

यह CentOS पर चल रहा है और संकलित रूप में सी

+0

संभावित (बेहतर) डुप्लिकेट [दो प्रक्रियाओं को दोहराएं] (http://stackoverflow.com/questions/1842909/fopen-two-processes)। – blahdiblah

+0

यह भी देखें [क्या एकाधिक प्रक्रियाएं किसी भी समवर्ती समस्याओं के बिना फॉपेन का उपयोग करके फ़ाइल में संलग्न हो सकती हैं?] (Http://stackoverflow.com/questions/7552451/can-multiple-processes-append-to-a-file-using-fopen- बिना-किसी भी-संगामिति-समस्या)। – blahdiblah

+2

मुझे आपके लॉग के उपयोग के संदर्भ को नहीं पता है, लेकिन मैं 'syslog' पर एक नज़र डालने की सलाह दूंगा। शायद यह आपको उपयुक्त बनाता है। इसके साथ काम करना वास्तव में सरल है। http://www.gnu.org/software/libc/manual/html_node/Submitting-Syslog-Messages.html –

उत्तर

8

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

write(2) कॉल ही अच्छी तरह से व्यवहार करना चाहिए:

[...] If the file was 
    open(2)ed with O_APPEND, the file offset is first set to the 
    end of the file before writing. The adjustment of the file 
    offset and the write operation are performed as an atomic 
    step. 

    POSIX requires that a read(2) which can be proved to occur 
    after a write() has returned returns the new data. Note that 
    not all file systems are POSIX conforming. 

इस प्रकार आपके मौलिक write(2) कॉल ठीक से व्यवहार करेंगे।

उच्च स्तरीय सी मानक आईओ धाराओं के लिए, आपको बफरिंग का भी ख्याल रखना होगा। setvbuf(3) फ़ंक्शन का उपयोग अप्रयुक्त आउटपुट, लाइन-बफर आउटपुट, या ब्लॉक-बफर आउटपुट का अनुरोध करने के लिए किया जा सकता है। डिफ़ॉल्ट व्यवहार धारा से स्ट्रीम में बदल जाता है - यदि मानक आउटपुट और मानक त्रुटि टर्मिनल पर लिख रही है, तो वे डिफ़ॉल्ट रूप से लाइन-buffered और unbuffered हैं। अन्यथा, ब्लॉक-बफरिंग डिफ़ॉल्ट है।

इंटरलीव किए गए डेटा को रोकने के लिए, यदि आपका डेटा स्वाभाविक रूप से रेखा-उन्मुख है, तो आप लाइन-बफर किए गए मैन्युअल रूप से चुन सकते हैं।यदि आपका डेटा लाइन उन्मुख नहीं है, तो आप un-buffered का उपयोग करना चाहेंगे या इसे ब्लॉक-buffered छोड़ सकते हैं, लेकिन जब भी आप आउटपुट की एक "इकाई" जमा करते हैं तो डेटा को मैन्युअल रूप से फ़्लश करें।

यदि आप एक समय में BUFSIZ बाइट्स से अधिक लिख रहे हैं, तो आपके लेखन अंतःस्थापित हो सकते हैं। setvbuf(3) फ़ंक्शन इंटरलिविंग को रोकने में मदद कर सकता है।

प्रदर्शन के बारे में बात करने में समय हो सकता है, लेकिन ब्लॉक बफरिंग ब्लॉक बफरिंग से धीमी हो रही है। यदि आप डिस्क की गति के करीब लॉगिंग कर रहे हैं, तो आप यह सुनिश्चित करने के लिए पूरी तरह से एक और दृष्टिकोण लेना चाहेंगे कि आपके लेखन इंटरलीव नहीं हैं।

+0

'setvbuf()' और इसके रूपों 'setbuf() ',' setbuffer() ', और' setlinebuf()' के बारे में महान युक्ति। वे वही थे जो मुझे चाहिए था। धन्यवाद, @ कर्नाल्ड। –

+0

यह इंगित करने के लिए धन्यवाद कि फ़ाइल ऑफ़सेट के परमाणु समायोजन की गारंटी के लिए O_APPEND की आवश्यकता है। मैंने इसे पहली प्रक्रिया से छोड़ा जो फ़ाइल खोलता है, क्योंकि यह इसे भी बनाता है (इसलिए 'संलग्न' उचित प्रतीत नहीं होता ..) – RobM

1

यह उत्तर गलत था है। यह करता है काम:

तो रेस स्थिति होगा:

  1. प्रक्रिया 1, संलग्न के लिए खुलता है तो
  2. बाद में प्रक्रिया 2, फिर संलग्न के लिए खुलता है
  3. बाद में अभी भी 1 राईट और बंद हो जाता है, फिर
  4. अंततः 2 लिखता है और बंद हो जाता है।

अगर मैं 'काम' करता हूं तो मुझे प्रभावित होगा क्योंकि यह मुझे स्पष्ट नहीं है कि काम करना चाहिए। मुझे लगता है कि 'काम करने' का मतलब है कि दो प्रक्रियाओं द्वारा लिखा गया सभी बाइट inthe लॉग फ़ाइल हैं? मैं उम्मीद करता हूं कि वे दोनों एक ही बाइट ऑफ़सेट से लिखते हैं, इसलिए कोई अन्य बाइट्स को प्रतिस्थापित करेगा। यह सभी चरण 3 सहित ठीक होगा और केवल चरण 4 पर एक समस्या के रूप में दिखाएं, लिखने के लिए एक आसान परीक्षण की तरह लगता है: खुले गेटचर ... करीब लिखें।

क्या यह महत्वपूर्ण है कि वे फ़ाइल को एक साथ खोल सकें? एक अधिक स्पष्ट समाधान यदि लेखन त्वरित है, तो अनन्य खोलना है।

आपके सिस्टम पर एक त्वरित जांच के लिए, कोशिश:

/* write the first command line argument to a file called foo 
* stackoverflow topic 9880935 
*/ 

#include <stdio.h> 
#include <fcntl.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <string.h> 

int main (int argc, const char * argv[]) { 
    if (argc <2) { 
     fprintf(stderr, "Error: need some text to write to the file Foo\n"); 
     exit(1); 
    } 

    FILE* fp = freopen("foo", "a+", stdout); 

    if (fp == NULL) { 
     perror("Error failed to open file\n"); 
     exit(1); 
    } 

    fprintf(stderr, "Press a key to continue\n"); 
    (void) getchar();  /* Yes, I really mean to ignore the character */ 

    if (printf("%s\n", argv[1]) < 0) { 
     perror("Error failed to write to file: "); 
     exit(1);   
    } 

    fclose(fp); 

    return 0; 
} 
+0

वे 'मैन फ्रॉपन' से एक-दूसरे को ओवरराइट नहीं करते हैं: 'ए + ... बाद में फ़ाइल को लिखता है हमेशा फाइल के तत्कालीन अंत में समाप्त हो जाएगा। – blahdiblah

+0

@blahdiblah - शायद मुझे कुछ याद आ रहा है, लेकिन वे मेरे उदाहरण में ** ** कैसे ओवरराइट कर सकते हैं? दोनों प्रक्रियाएं संलग्न करने के लिए खुली हैं, लेकिन उस चरण में कोई भी बाइट नहीं लिखती हैं, और इसलिए फ़ाइल खुलने के लिए एक ही लंबाई है। फिर वे दोनों लिखते हैं। क्या फ़ाइल fd की विशेषता ऑफ़सेट नहीं है, न कि फ़ाइल? – gbulmer

+0

मैं केवल मैन पेज में जानकारी, और अपने स्वयं के परीक्षण के परिणाम की रिपोर्ट करता हूं। मैं अंतर्निहित कार्यान्वयन विवरण से बात नहीं कर सकता। – blahdiblah

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