سؤال

لدي تطبيق يحتوي على موضوعين.

الأول (الخيط الرئيسي) الذي يلتقط البيانات باستخدام المقبس وتحديث DataTables

الثاني يقوم بإدراج DataTables في قاعدة البيانات.

يعمل التطبيق بشكل جيد ولكن عند إغلاقه، ينتهي الخيط الرئيسي من قراءة البيانات ويستدعي أسلوب Abort في الخيط الثاني، والذي قد يتم إدراجه في قاعدة البيانات وهذا يؤدي إلى بيانات غير متناسقة.

أستخدم حاليًا الحل التالي للتغلب على "الإجهاض أثناء الإدراج"

يحرر:بعد الإجابات القوية قمت بتغيير الكود

void MainThread()
{
     while(Read())
     {
        //Read Data through socket
        try
        {
           //Wait on Mutex1
           //Update Tables
        }
        finally
        {
          //Release Mutex1
        }
     }
   _isrunning = false;
   _secondThread.Join();
}
void SecondThread()
{
     while(_isrunning)
     {
        try
        {
           //Wait on Mutex1
           //Insert Tables into Database using transactions
        }
        finally
        {
           //Release Mutex1           
        }
     }
}
هل كانت مفيدة؟

المحلول

بافتراض أن "أسلوب إحباط الاستدعاء" يعني إحباط مؤشر الترابط باستخدام Thread.Abort. لا تفعل ذلك.

أنت تعطل التطبيق الخاص بك بشكل فعال.هناك الكثير من الطرق النظيفة للقيام بذلك باستخدام الشاشات.

ومع ذلك، يجب ألا تحصل على بيانات غير متناسقة في قاعدة البيانات الخاصة بك عندما يتعطل تطبيقك ولهذا السبب لديك معاملات قاعدة البيانات التي لها حامض ملكيات.

تعديل مهم جداأنت قلت:لا تستخدم المعاملات لأسباب تتعلق بالأداء، بل تستخدم كائنات المزامنة بدلاً من ذلك.هذا هو خطأ على عدد غير قليل من المستويات.أولاً، يمكن للمعاملات أن تجعل عمليات معينة أسرع، على سبيل المثال، حاول إدراج 10 صفوف في جدول، ثم حاول مرة أخرى داخل المعاملة، وسيكون إصدار المعاملة أسرع.ثانيًا، ماذا يحدث عندما/إذا تعطل تطبيقك، هل يؤدي ذلك إلى إتلاف قاعدة بياناتك؟ماذا يحدث عند تشغيل مثيلات متعددة لتطبيقك؟أو أثناء تشغيل التقارير ضد قاعدة البيانات الخاصة بك في محلل الاستعلام؟

نصائح أخرى

طالما لم يتم وضع علامة على كلا الخيطين كسلاسل خلفية، سيستمر التطبيق في العمل حتى يتم الخروج من كلا الخيطين.لذا، كل ما عليك فعله حقًا هو إخراج كل مؤشر ترابط بشكل منفصل للخروج بشكل نظيف.في حالة الخيط الذي يكتب إلى قاعدة البيانات، قد يعني هذا استنفاد قائمة انتظار المنتج/المستهلك والتحقق من العلامة للخروج.

لقد أظهرت قائمة انتظار مناسبة للمنتج/المستهلك هنا - العامل سيكون فقط:

void WriterLoop() {
    SomeWorkItem item; // could be a `DataTable` or similar
    while(queue.TryDequeue(out item)) {
        // process item
    }
    // queue is empty and has been closed; all done, so exit...
}

فيما يلي مثال كامل يعتمد على SizeQueue<> - لاحظ أن العملية لا تخرج إلا عند القارئ و لقد خرج الكاتب نظيفًا.إذا كنت لا تريد أن تضطر إلى استنزاف قائمة الانتظار (أي.تريد الخروج عاجلاً، ونسيان أي عمل معلق)، فلا بأس - أضف علامة (متقلبة) إضافية في مكان ما.

static class Program {
    static void Write(object message) {
        Console.WriteLine(Thread.CurrentThread.Name + ": " + message);
    }
    static void Main() {
        Thread.CurrentThread.Name = "Reader";
        Thread writer = new Thread(WriterLoop);
        writer.Name = "Writer";
        var queue = new SizeQueue<int>(100);
        writer.Start(queue);
        // reader loop - note this can run parallel
        // to the writer
        for (int i = 0; i < 100; i++) {
            if (i % 10 == 9) Write(i);
            queue.Enqueue(i);
            Thread.Sleep(5); // pretend it takes time
        }
        queue.Close();
        Write("exiting");
    }
    static void WriterLoop(object state) {
        var queue = (SizeQueue<int>)state;
        int i;
        while (queue.TryDequeue(out i)) {
            if(i%10==9) Write(i);
            Thread.Sleep(10); // pretend it takes time
        }
        Write("exiting");
    }
}

ومزامنة الانتظار الخاصة بك ينبغي أن تنطوي على المهلة. حلقة خارجية كل موضوع يمكن أن تحقق ل"الرجاء إغلاق الآن 'العلم. لاغلاق، مجموعة 'الرجاء إغلاق الآن' العلم لكل موضوع، ثم استخدم "الانضمام" لانتظار كل موضوع لإنهاء.

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