दिलचस्प पोस्ट
एपैंपपेट v7 के साथ संपादन टेक्स्ट नीचे पंक्ति रंग परिवर्तित करना डेल्फी रूपांतरण यूनिकोड मुद्दे वेबव्यू के अंदर एक पीडीएफ फाइल खोलें। आप सी में स्ट्रैक्ट्स की एक सरणी कैसे बनाते हैं? सीएसएस ढेरिंग मार्जिन का क्या मतलब है? पायथन पर कीबोर्ड और माउस अनुकरण करने का सबसे आसान तरीका कौन सा है? IOS 7 UIImagePickerController का काला पूर्वावलोकन है String.Format StringBuilder के रूप में कुशल है एंड्रॉइड पर जावा कोड हालांकि शैल आदेश चल रहा है? Matplotlib में रंग चक्र रीसेट करें एक इंटरफ़ेस को कार्यान्वित करने वाले जावा वर्गों का पता लगाएं कमांड प्रॉम्प्ट कैसे खोलें और जावा का उपयोग करके कमांड डालें? फ़ाइल खोज में regex का उपयोग कैसे करें पुश अधिसूचना बैज iPhone बढ़ाना स्थानीय फ़ाइलों के लिए xmlhttprequest

एक स्थानीय फाइल सिस्टम पर `लिखने (2)` परमाणुता

जाहिर है कि पॉसिक्स बताता है कि

या तो एक फाइल डिस्क्रिप्टर या एक स्ट्रीम को खुले फ़ाइल विवरण पर "हैंडल" कहा जाता है, जिस पर यह संदर्भित होता है; एक खुला फ़ाइल विवरण में कई हैंडल हो सकते हैं […] पहली संभाल पर ऑफ़सेट फाइल को प्रभावित करने वाले आवेदन द्वारा की गई सभी गतिविधि को तब तक निलंबित कर दिया जाएगा जब तक यह फिर से सक्रिय फ़ाइल संभाल न हो जाए। […] इन नियमों को लागू करने के लिए हैंडल को उसी प्रक्रिया में नहीं होना चाहिए – POSIX.1-2008

तथा

यदि दो धागे प्रत्येक कॉल [लिखने () फ़ंक्शन], तो प्रत्येक कॉल अन्य कॉल के सभी निर्दिष्ट प्रभावों को देखेगी, या उनमें से कोई भी नहीं। – POSIX.1-2008

इसकी मेरी समझ यह है कि जब पहली प्रक्रिया एक write(handle, data1, size1) और दूसरी प्रक्रिया के मुद्दों को write(handle, data2, size2) , तो लिखते हैं किसी भी क्रम में हो सकता है, लेकिन data1 और data1 दोनों को पुराना होना चाहिए और निकटतम

लेकिन निम्न कोड चलाने से मुझे अप्रत्याशित परिणाम मिलते हैं I

 #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <unistd.h> #include <sys/wait.h> die(char *s) { perror(s); abort(); } main() { unsigned char buffer[3]; char *filename = "/tmp/atomic-write.log"; int fd, i, j; pid_t pid; unlink(filename); /* XXX Adding O_APPEND to the flags cures it. Why? */ fd = open(filename, O_CREAT|O_WRONLY/*|O_APPEND*/, 0644); if (fd < 0) die("open failed"); for (i = 0; i < 10; i++) { pid = fork(); if (pid < 0) die("fork failed"); else if (! pid) { j = 3 + i % (sizeof(buffer) - 2); memset(buffer, i % 26 + 'A', sizeof(buffer)); buffer[0] = '-'; buffer[j - 1] = '\n'; for (i = 0; i < 1000; i++) if (write(fd, buffer, j) != j) die("write failed"); exit(0); } } while (wait(NULL) != -1) /* NOOP */; exit(0); } 

मैंने इसे लिनक्स और मैक ओएस एक्स 10.7.4 पर चलाने की कोशिश की और grep -a '^[^-]\|^..*-' /tmp/atomic-write.log दिखाया गया है कि कुछ लिखते हैं निकट या ओवरलैप नहीं ( लिनक्स) या सादा भ्रष्ट (मैक ओएस एक्स)।

open(2) में ध्वज O_APPEND जोड़ना open(2) कॉल इस समस्या को हल करता है अच्छा, लेकिन मुझे समझ में नहीं आता कि क्यों पॉसिक्स कहते हैं

O_APPEND यदि सेट किया गया है, तो फ़ाइल ऑफ़सेट को प्रत्येक लिखने से पहले फ़ाइल के अंत में सेट किया जाएगा।

लेकिन यह समस्या यहाँ नहीं है मेरा नमूना कार्यक्रम lseek(2) कभी नहीं करता है, लेकिन समान फाइल विवरण साझा करता है और इसी प्रकार ऑफसेट ऑफसेट।

मैंने पहले से ही स्टैकवॉवरफ्लो पर ऐसे प्रश्नों को पढ़ा है लेकिन वे अब भी मेरे प्रश्न का पूरी तरह जवाब नहीं देते हैं

दो प्रक्रियाओं से फ़ाइल पर परमाणु लिखना, विशेष रूप से उस केस को संबोधित नहीं करता है जहां प्रक्रियाएं समान फ़ाइल विवरण साझा करती हैं (उसी फ़ाइल के विपरीत)।

कैसे किसी प्रोग्राम को यह निर्धारित करता है कि "लिखना" सिस्टम कॉल किसी विशेष फ़ाइल पर परमाणु है? कहता है कि

POSIX में परिभाषित के रूप में write कॉल बिल्कुल परमाणु की गारंटी नहीं है

लेकिन जैसा कि ऊपर बताया गया है उसके पास कुछ है और क्या अधिक है, O_APPEND इस परमाणु की गारंटी को ट्रिगर करता है, हालांकि मुझे लगता है कि यह गारंटी भी बिना O_APPEND मौजूद होना चाहिए।

क्या आप इस व्यवहार को आगे बता सकते हैं?

वेब के समाधान से एकत्रित समाधान "एक स्थानीय फाइल सिस्टम पर `लिखने (2)` परमाणुता"

man 2 write मेरे सिस्टम पर man 2 write यह अच्छी तरह से sums:

ध्यान दें कि सभी फाइल सिस्टम POSIX अनुरूप नहीं हैं।

ext4 मेलिंग सूची पर एक हालिया चर्चा से यहां एक उद्धरण है:

वर्तमान में समवर्ती पढ़ता है / लिखते हैं परमाणु केवल wrt व्यक्तिगत पृष्ठों, हालांकि सिस्टम कॉल पर नहीं हैं। इसके कारण कई अलग-अलग लिखतों से मिश्रित डेटा वापस करने के लिए read() सकते हैं, जो मुझे नहीं लगता कि यह अच्छा दृष्टिकोण है। हम यह तर्क दे सकते हैं कि ऐसा करने के लिए आवेदन टूटा हुआ है, लेकिन वास्तव में यह कुछ ऐसा है जो हम आसानी से फाइल सिस्टम स्तर पर बिना महत्वपूर्ण प्रदर्शन समस्याओं के कर सकते हैं, इसलिए हम लगातार हो सकते हैं। इसके अलावा पॉसिक्स इस रूप में अच्छी तरह से उल्लेख करते हैं और एक्सएफएस फाइल सिस्टम में पहले से ही यह सुविधा है।

यह एक स्पष्ट संकेत है कि ext4 – सिर्फ एक आधुनिक फाइल सिस्टम के नाम से – इस संबंध में POSIX.1-2008 के अनुरूप नहीं है।

कुछ मानकों के बारे में कुछ गलत व्याख्या है कि ये प्रक्रियाओं के उपयोग से मानक नियम बनाते हैं, और इसका मतलब "हैंडल" स्थिति के बारे में है जो आप के बारे में बात कर रहे हैं। विशेष रूप से, आपने इस भाग को याद किया:

अंतर्निहित खुली फाइल विवरण को प्रभावित किए बिना, स्पष्ट उपयोगकर्ता कार्रवाई द्वारा संभाल या नष्ट किया जा सकता है। उनमें से कुछ तरीके बनाने के लिए fcntl (), dup (), fdopen (), fileno (), और fork() शामिल हैं उन्हें कम से कम fclose (), close (), और exec फ़ंक्शंस द्वारा नष्ट किया जा सकता है। […] ध्यान दें कि एक कांटा () के बाद, दो हैंडल मौजूद हैं जहां पहले एक मौजूद था।

पॉसिक्स स्पेक से आपको उपरोक्त विवरण इस खंड में "बनाने [का उपयोग करने वाले हैंडल्स]" का संदर्भ आगे नहीं विस्तारित किया गया है, लेकिन fork() लिए युक्ति थोड़ा विस्तार जोड़ता है:

बाल प्रक्रिया की माता-पिता की फ़ाइल विवरणक की अपनी प्रति होगी। प्रत्येक बच्चे की फाइल विवरणकर्ता माता-पिता के संबंधित फाइल डिस्क्रिप्टर के साथ एक समान खुले फ़ाइल विवरण का उल्लेख करेंगे।

संबंधित बिट्स यहां हैं:

  • बच्चे की माता-पिता की फाइल विवरणकर्ता की प्रतियां हैं
  • बच्चे की प्रतियां एक ही "बात" का उल्लेख करती हैं जो कि माता-पिता ने एफडीए कहा है
  • फ़ाइल descript ors और फ़ाइल descript आयन्स एक ही बात नहीं हैं; विशेष रूप से, एक फाइल डिस्क्रिप्टर उपरोक्त अर्थों में एक हैंडल है

यह पहला उद्धरण है, जब यह कहता है कि " fork() बनाता है […] हैंडल" – वे प्रतियों के रूप में बनाए गए हैं, और इसलिए, उस बिंदु पर, अलग , और अब लॉकस्टेप में अपडेट नहीं किया गया है।

आपके उदाहरण कार्यक्रम में, प्रत्येक बच्चे की प्रक्रिया अपनी प्रतिलिपि प्राप्त करती है जो एक ही राज्य से शुरू होती है, लेकिन प्रतिलिपि के कार्य के बाद, इन दायर दासता / हैंडल स्वतंत्र उदाहरण बन गए हैं, और इसलिए एक दूसरे के साथ दौड़ लिखती है यह मानक के बारे में पूरी तरह से स्वीकार्य है, क्योंकि write() केवल निर्देशन:

एक नियमित फ़ाइल या अन्य फ़ाइल की मांग करने में सक्षम, डेटा की वास्तविक लिखित फाइल फ़िलिड्स से जुड़ी ऑफसेट फाइल द्वारा दर्शाई गई फ़ाइल में से आगे बढ़नी होगी। लिखने से सफल वापसी से पहले, ऑफसेट फाइल वास्तव में लिखी गई बाइट्स की संख्या से बढ़ी जाएगी।

इसका मतलब यह है कि जब तक वे सभी एक ही ऑफसेट पर लिखना शुरू करते हैं (क्योंकि एफडी कॉपी इन्हें आरंभ किया गया था), भले ही सफल हो, सभी अलग-अलग रकम लिखते हैं (मानक द्वारा कोई गारंटी नहीं है कि N बाइट्स का एक लिखने का अनुरोध लिखा जाएगा ठीक N बाइट्स, यह किसी भी चीज़ के लिए सफल हो सकता है 0 <= वास्तविक <= N ), और लिखने के आदेश के कारण अनिर्दिष्ट है, इसलिए ऊपर के पूरे उदाहरण कार्यक्रम में अनिर्दिष्ट परिणाम हैं। यहां तक ​​कि कुल अनुरोधित राशि लिखी जाने पर भी, सभी मानक ऊपर बताते हैं कि फ़ाइल ऑफसेट बढ़ी है – यह नहीं कहता कि यह परमाणु रूप से (एक बार केवल) बढ़ता है, और न ही यह कहता है कि डेटा का वास्तविक लेखन एक परमाणु फैशन में होगा

हालांकि एक बात की गारंटी है – आपको फ़ाइल में कुछ भी नहीं दिखना चाहिए जो कि किसी भी लिखने से पहले या तो नहीं है, या जो किसी भी लिखते हुए लिखित डेटा से नहीं आया था। यदि आप करते हैं, तो वह भ्रष्टाचार होता है, और फाइल सिस्टम कार्यान्वयन में एक बग होता है जो आपने ऊपर देखा है वह अच्छी तरह से हो सकता है … अगर अंतिम परिणामों को लिखने के कुछ हिस्सों के पुन: आदेश द्वारा समझाया नहीं जा सकता है

O_APPEND का उपयोग O_APPEND ठीक करता है, क्योंकि इसका उपयोग करना, फिर से – write() देखें, करता है:

यदि फ़ाइल स्टेटस झंडे के O_APPEND ध्वज को सेट किया गया है, तो फ़ाइल ऑफसेट को प्रत्येक लिखने से पहले फाइल के अंत में सेट किया जाएगा और फ़ाइल ऑफसेट और लेखन ऑपरेशन को बदलने के बीच कोई हस्तक्षेप करने वाली फाइल संशोधन प्रक्रिया नहीं होगी।

जो "पूर्व से" / "कोई हस्तक्षेप नहीं" धारावाहिक व्यवहार है जो आप चाहते हैं।

धागे का उपयोग आंशिक रूप से व्यवहार को बदल देगा – क्योंकि धागे, निर्माण पर, दायर दास / प्रतिलिपि की प्रतियां प्राप्त नहीं करते हैं, लेकिन वास्तविक (साझा) एक पर काम करते हैं थ्रेड्स (जरूरी नहीं) सभी ऑफसेट पर लिखना शुरू करेंगे लेकिन आंशिक-लेखन-सफलता के लिए विकल्प का अभी भी मतलब होगा कि आप उन तरीकों से द्विवाही देख सकते हैं जिन्हें आप देखना नहीं चाहते हैं। फिर भी यह संभवतः अभी भी पूरी तरह से मानकों-अनुरूप होना होगा।

नैतिक : एक पॉसिक्स / यूनिक्स मानक पर भरोसा न करें, जो डिफ़ॉल्ट रूप से प्रतिबंधात्मक होता है । विनिर्देश सामान्य मामले में जान-बूझकर आराम कर रहे हैं, और प्रोग्रामर को आपके इरादे के बारे में स्पष्ट होने के लिए आपको आवश्यक है।

संपादित करें: ओएस व्यवहार में नवीनतम परिवर्तनों के साथ अगस्त 2017 को अपडेट किया गया।

सबसे पहले, O_APPEND या Windows पर समतुल्य FILE_APPEND_DATA का अर्थ है कि अधिकतम फ़ाइल हद तक वृद्धि (फ़ाइल "लंबाई") समवर्ती लेखकों के अंतर्गत परमाणु होती है । इसे पॉसिक्स की गारंटी है, और लिनक्स, फ्रीबीएसडी, ओएस एक्स और विंडोज़ इसे सही ढंग से लागू करते हैं। साम्बा ने इसे सही ढंग से लागू किया है, वी 5 से पहले एनएफटी नहीं है क्योंकि यह परमाणु रूप से संलग्न करने के लिए वायर प्रारूप क्षमता का अभाव है। इसलिए यदि आप केवल अपनी फाइल संलग्नक के साथ खोलते हैं, तो एनएसएस शामिल होने तक किसी भी प्रमुख ओएस पर एक दूसरे के साथ समसामयिक लिखना नहीं झेलगा

यह इस बारे में कुछ भी नहीं कहता कि क्या पढ़ता है, कभी भी एक फाड़ लिखने को दिखाई देगा, और उस पॉसिक्स पर नियमित फाइलों पर पढ़ने () लिखने और लिखने के बारे में कहा गया है:

POSIX.1-2008 में निर्दिष्ट प्रभावों में निम्नलिखित कार्यों में से प्रत्येक परमाणु एक दूसरे के संबंध में परमाणु होगा जब वे नियमित फाइलों या प्रतीकात्मक लिंक पर काम करते हैं … [कई फ़ंक्शंस] … पढ़ें () … लिखना ( ) … यदि दो धागे इनमें से प्रत्येक फ़ंक्शन पर कॉल करते हैं, तो प्रत्येक कॉल अन्य कॉल के सभी निर्दिष्ट प्रभावों को देखेगी, या उनमें से कोई भी नहीं होगा। [स्रोत]

तथा

अन्य लेखन और लिखने के संबंध में लेखन को सीरियल किया जा सकता है यदि डेटा के एक लिखने के बाद होने वाली फ़ाइल डेटा का कोई भी पठन () किसी भी तरह से साबित किया जा सकता है, तो उसे लिखना () को प्रतिबिंबित करना चाहिए, भले ही कॉल विभिन्न प्रक्रियाओं द्वारा किया जाता है [स्रोत]

लेकिन इसके विपरीत:

POSIX.1-2008 का यह वॉल्यूम एकाधिक प्रक्रियाओं से एक फ़ाइल में समवर्ती लेखन के व्यवहार को निर्दिष्ट नहीं करता है। अनुप्रयोगों को किसी प्रकार के संगामिति नियंत्रण का उपयोग करना चाहिए। [स्रोत]

इन तीनों आवश्यकताओं की एक सुरक्षित व्याख्या यह सुझाव देगी कि सभी एक ही फाइल में एक हद तक ओवरलैपिंग लिखते हैं, उन्हें एक दूसरे के संबंध में क्रमबद्ध किया जाना चाहिए और ऐसे पाठ पढ़ा जाए जो फाड़ लिखने वाले पाठकों को कभी नहीं दिखाई देते।

एक कम सुरक्षित, लेकिन फिर भी अनुमति दी जाने वाली व्याख्या हो सकती है कि एक ही प्रक्रिया के भीतर थ्रेड के बीच एक दूसरे के साथ सीरियलिज पढ़ता है और लिखता है, प्रक्रियाओं के बीच केवल पढ़ने के संबंध में क्रमबद्ध होते हैं (अर्थात क्रमिक रूप से सुसंगत I / O में धागे के बीच क्रम है एक प्रक्रिया है, लेकिन प्रक्रियाओं के बीच I / O केवल-प्राप्त होता है)।

तो कैसे लोकप्रिय ओएस और फाइल सिस्टम इस पर प्रदर्शन करते हैं? प्रस्तावित Boost.AFIO के लेखक के रूप में एक एसिंक्रोनस फाइलसिस्टम और फाइल आई / ओ सी ++ लाइब्रेरी, मैंने एक अनुभवजन्य परीक्षक लिखने का निर्णय लिया है। परिणाम एक ही प्रक्रिया में कई धागे के लिए निम्नानुसार हैं


नहीं, O_DIRECT / FILE_FLAG_NO_BUFFERING:

माइक्रोसॉफ्ट विंडोज 10 एनटीएफएस के साथ: अद्यतन एटॉमीटीटी = 1 बाइट तक और 10.0.10240 सहित, 10.0.14393 से कम से कम 1 एमबी, संभवतः पॉसिक्स स्पेस के अनुसार अनंत।

लिनक्स 4.2.6 एक्सटी 4: अपडेट एटमिटिटी = 1 बाइट

फ्री बीएसडी 10.2 जेडएफएस के साथ: अद्यतन एटमॉसिटी = कम से कम 1 एमबी, संभवतः पीओएसआईएसआईक्स स्पेस के अनुसार अनंत है।

O_DIRECT / FILE_FLAG_NO_BUFFERING:

माइक्रोसॉफ्ट विंडोज 10 एनटीएफएस के साथ: अद्यतन एटॉमीसीटी = तक और 10.0.10240 तक 4096 बाइट्स तक केवल पेज संरेखित होने पर, अन्यथा 512 बाइट्स यदि FILE_FLAG_WRITE_THROUGH बंद, अन्य 64 बाइट्स ध्यान दें कि इस परमाणुता शायद पीसीआईई डीएमए की विशेषता है, जो कि डिजाइन किए जाने के बजाय। 10.0.14393 से, कम से कम 1 एमबी, संभवतः पीओएसआईएसआईक्स स्पेस के अनुसार अनंत है।

लिनक्स 4.2.6 एक्सटी 4: अद्यतन एटमिटिटी = कम से कम 1 एमबी, संभवतः पीओएसआईएसआईक्स स्पेस के अनुसार अनंत है। नोट करें कि ext4 के साथ पूर्व लिनक्सक्स निश्चित रूप से 4096 बाइट्स से अधिक नहीं थे, एक्सएफएस निश्चित रूप से कस्टम ताला लगाते थे लेकिन ऐसा लगता है कि हालिया लिनक्स ने अंततः इस समस्या को ext4 में तय किया है।

फ्री बीएसडी 10.2 जेडएफएस के साथ: अद्यतन एटमॉसिटी = कम से कम 1 एमबी, संभवतः पीओएसआईएसआईक्स स्पेस के अनुसार अनंत है।


तो संक्षेप में, ZFS के साथ FreeBSD और NTFS के साथ हाल ही में Windows POSIX अनुरूप है। बहुत हाल के लिनक्स के साथ ext4 POSIX केवल O_DIRECT के अनुरूप है।

आप https://github.com/ned14/afio/tree/master/programs/fs-probe पर कच्चे अनुभवजन्य परीक्षण परिणाम देख सकते हैं। नोट हम केवल 512 बाइट गुणकों पर फाड़ ऑफसेट के लिए परीक्षण करते हैं, इसलिए मैं यह नहीं कह सकता कि 512 बाइट क्षेत्र का आंशिक अद्यतन पढ़ने-संशोधित-लिखने के चक्र के दौरान आंसू जाएगा।

आप जिस उद्धरण के उद्धरण के पहले भाग का गलत अर्थ बता रहे हैं:

या तो एक फाइल डिस्क्रिप्टर या एक स्ट्रीम को खुले फ़ाइल विवरण पर "हैंडल" कहा जाता है, जिस पर यह संदर्भित होता है; एक खुला फ़ाइल विवरण में कई हैंडल हो सकते हैं […] पहली संभाल पर ऑफ़सेट फाइल को प्रभावित करने वाले आवेदन द्वारा की गई सभी गतिविधि को तब तक निलंबित कर दिया जाएगा जब तक यह फिर से सक्रिय फ़ाइल संभाल न हो जाए। […] इन नियमों को लागू करने के लिए हैंडल को उसी प्रक्रिया में नहीं होना चाहिए

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

केवल समय परमाणुता की गारंटी पाइप के लिए है, जब लिखने का आकार PIPE_BUF में फिट PIPE_BUF

वैसे, भले ही कॉल write लिए सामान्य फाइलों के लिए परमाणु थे, सिवाय PIPE_BUF में पाइप के लिए write के मामले में, write हमेशा एक आंशिक लिखे (यानी बाइट्स की अनुरोधित संख्या से कम लिखा हुआ हो) के साथ वापस आ सकता है। यह छोटा-से-अनुरोधित लेखन तो परमाणु होगा, लेकिन यह पूरे ऑपरेशन के परमाणु के संबंध में स्थिति को बिल्कुल भी मदद नहीं करेगा (आपके आवेदन को पुनः write लिए write होगा)।