شرح التغيير إلى GNU C ++ FileBuf :: underflow () التفاعل مع FileBuf :: Seekoff ()

StackOverflow https://stackoverflow.com/questions/3678010

  •  01-10-2019
  •  | 
  •  

سؤال

تعمل منتجات شركتي على عدد من تكوينات الأجهزة/البرامج Linux المؤهلة. تاريخيا ، كان المترجم المستخدم GNU C ++. لأغراض هذا المنشور ، دعنا ننظر في الإصدار 3.2.3 الأساس ، حيث كان برنامجنا "يعمل كما هو متوقع" من خلال هذا الإصدار.

مع إدخال منصة مؤهلة أحدث ، باستخدام الإصدار 3.4.4 GNU C ++ ، بدأنا في ملاحظة بعض مشاكل الأداء التي لم نرها من قبل. بعد بعض الحفر ، توصل أحد مهندسينا إلى برنامج الاختبار هذا:

#include <fstream>
#include <iostream>

using namespace std;

class my_filebuf : public filebuf
{
public:

   my_filebuf() : filebuf(), d_underflows(0) {};
   virtual ~my_filebuf() {};

   virtual pos_type seekoff(off_type, ios_base::seekdir,
                            ios_base::openmode mode = ios_base::in | ios_base::out);

   virtual int_type underflow();

public:
   unsigned int d_underflows;
};

filebuf::pos_type my_filebuf::seekoff(
   off_type           off,
   ios_base::seekdir  way,
   ios_base::openmode mode
)
{
   return filebuf::seekoff(off, way, mode);
}

filebuf::int_type my_filebuf::underflow()
{
   d_underflows++;

   return filebuf::underflow();
}

int main()
{
   my_filebuf fb;
   fb.open("log", ios_base::in);
   if (!fb.is_open())
   {
      cerr << "need log file" << endl;
      return 1;
   }

   int count = 0;
   streampos pos = EOF;
   while (fb.sbumpc() != EOF)
   {
      count++;

      // calling pubseekoff(0, ios::cur) *forces* underflow
      pos = fb.pubseekoff(0, ios::cur);
   }

   cerr << "pos=" << pos << endl;
   cerr << "read chars=" << count << endl;
   cerr << "underflows=" << fb.d_underflows << endl;

   return 0;
}

قمنا بتشغيله مقابل ملف سجل يبلغ حوالي 751 كيلو بايت. في التكوينات السابقة ، حصلنا على النتيجة:

$ buftest
pos=768058
read chars=768058
underflows=0

في الإصدار الأحدث ، والنتيجة هي:

$ buftest
pos=768058
read chars=768058
underflows=768059

التعليق على PubSeekoff (0 ، iOS :: cur) الدعوة والإفراط underflow () المكالمات تذهب بعيدا. من الواضح أنه في إصدارات أحدث من G ++ ، الاتصال PubSeekoff () "يبطل" المخزن المؤقت ، مما يجبر على المكالمة underflow ().

لقد قرأت وثيقة المعايير ، والشفرة على PubSeekoff () بالتأكيد غامض. ما هي علاقة مؤشر الملف الأساسي GPTR (), ، على سبيل المثال؟ قبل أو بعد، بعدما دعوة إلى underflow ()؟ بغض النظر عن هذا ، أجد أنه من المزعج أن G ++ "غيرت الخيول في منتصف الطريق" ، إذا جاز التعبير. علاوة على ذلك ، حتى لو جنرال لواء SeekOff () يتطلب إبطال المؤشرات العازلة ، لماذا يجب أن تعادل ما يعادل ftell ()?

هل يمكن لأي شخص أن يوجهني إلى موضوع مناقشة بين المنفذين الذي أدى إلى هذا التغيير في السلوك؟ هل لديك وصف مختصرة للخيارات والمقايضات المعنية؟

رصيد إضافي

من الواضح أنني لا أعرف ماذا أفعل. كنت أجرب لتحديد ما إذا كانت هناك طريقة ، مهما كانت غير قابلة للتحمول ، لتجاوز الإبطال في الحالة التي يكون فيها الإزاحة 0 و SeekDir iOS :: cur. لقد توصلت إلى الاختراق التالي ، والوصول مباشرة إلى filebuf عضو البيانات _m_file (أراد هذا فقط التجميع مع الإصدار 3.4.4 على الجهاز الخاص بي):

int sc(0);
filebuf::pos_type my_filebuf::seekoff(
   off_type           off,
   ios_base::seekdir  way,
   ios_base::openmode mode
)
{
   if ((off == 0) && (way == ios::cur))
   {
      FILE *file =_M_file.file();
      pos_type pos = pos_type(ftell(file));

      sc++;
      if ((sc % 100) == 0) {
         cerr << "POS IS " << pos << endl;
      }

      return pos;
   }

   return filebuf::seekoff(off, way, mode);
}

ومع ذلك ، فإن التشخيص لطباعة الموضع كل مائة البحث محاولات تعطي 8192 في كل مرة. هاه؟ لأن هذا هو ملف * عضو في filebuf نفسها ، أتوقع أن يكون مؤشر موضع الملف متزامنًا مع أي underflow () المكالمات التي أجراها filebuf. لماذا أنا مخطئ؟

تحديث

أولاً ، اسمحوا لي أن أؤكد أنني أفهم أن هذا الجزء اللاحق من رسالتي هو كل شيء عن الاختراقات غير المحمولة. ومع ذلك ، لا تفهم النزعة الدقيقة هنا. حاولت الاتصال

pos_type pos = _M_file.seekoff(0,ios::cur);

بدلا من ذلك ، وهذا بسعادة يتقدم من خلال ملف العينة ، بدلاً من التعثر في 8192.

التحديث النهائي

داخليًا لشركتي ، قمنا ببعض الحلول التي تقلل من الأداء الكافي الذي يمكننا العيش معه.

خارجيا ، قدم ديفيد كراوس أ حشرة ضد تدفقات LIBSTDC ++ من GNU ، ومؤخراً ، قام Paolo Carlini بالتحقق من الإصلاح. كان الإجماع على أن السلوك غير المرغوب فيه كان ضمن نطاق المعيار ، ولكن كان هناك حل معقول لحالة الحافة التي وصفتها.

لذا شكرًا ، Stackoverflow ، David Krauss ، Paolo Carlini ، وجميع مطوري GNU!

هل كانت مفيدة؟

المحلول

المتطلبات ل seekoff بالتأكيد مربكة ، ولكن seekoff(0, ios::cur) من المفترض أن تكون حالة خاصة لا تزامن أي شيء. لذلك ربما يمكن اعتبار هذا خطأ.

ولا يزال يحدث في مجلس التعاون الخليجي 4.2.1 و 4.5 ...

المشكلة هي (0, ios::cur) غير معتمد في _M_seek, ، أيّ seekoff يستخدم للاتصال fseek للحصول على قيمة الإرجاع. طالما أن هذا ينجح ، _M_seek مكالمات دون قيد أو شرط _M_set_buffer(-1);, ، والتي تنبأ بشكل متوقع المخزن المؤقت الداخلي. تسبب عملية القراءة التالية underflow.

وجدت الفرق! انظر التغيير -473,41 +486,26. كان التعليق

    (seekoff): Simplify, set _M_reading, _M_writing to false, call
    _M_set_buffer(-1) ('uncommitted').

لذلك لم يتم القيام بذلك لإصلاح الخلل.

علة المودعة: http://gcc.gnu.org/bugzilla/show_bug.cgi؟id=45628

نصائح أخرى

حسنًا ، لا أعرف السبب الدقيق للتغيير ، ولكن يبدو أن التغييرات تم إجراؤها (انظر GCC 3.4 Series Changelog):

  • Streamlined Streambuf ، FileBuf ، منفصل متزامن مع C القياسية I/O Streambuf.
  • دعم الملفات الكبيرة (ملفات أكبر من 2 غيغابايت على أنظمة 32 بت).

أظن أن دعم الملفات الكبير هو الميزة الكبيرة التي تتطلب تغييرًا كهذا ، لأن IoStreams لم يعد قادرًا على افتراض أنه يمكنه تعيين الملف بأكمله في الذاكرة.

المزامنة الصحيح مع cstdio هي أيضا عملية قد تتطلب عدد أكبر من التدفق على القرص. يمكنك تعطيل ذلك باستخدام std::sync_with_stdio.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top