Καλώς ορίσατε στο dotNETZone.gr - Σύνδεση | Εγγραφή | Βοήθεια
σε

 

Αρχική σελίδα Ιστολόγια Συζητήσεις Εκθέσεις Φωτογραφιών Αρχειοθήκες

SQLConnection Μέσα από Threads με το ίδιο SQLConnectionString

Îåêßíçóå áðü ôï ìÝëïò pontifikas. Τελευταία δημοσίευση από το μέλος pontifikas στις 29-12-2008, 21:18. Υπάρχουν 4 απαντήσεις.
Ταξινόμηση Δημοσιεύσεων: Προηγούμενο Επόμενο
  •  06-12-2008, 20:34 46752

    SQLConnection Μέσα από Threads με το ίδιο SQLConnectionString

    Προσπαθώ να δημιουργήσω threads τα οποία θα είναι σε θέση να κάνουν εγγραφές σε μια ΒΔ.
    Για αρχή δοκιμάζω το εξής απλό σενάριο:
    Φτοιάχνω 3 threads, στην Start Function δημιουργώ και ανοίγω ένα connection, ρίχνω ένα select query, γράφω τα αποτελεματα σε ένα DataTable
    και κάθε Thread γραφει το Table του σε ένα DataSet που είναι Global. Στην συνέχεια τα threads μπαίνουν σε ένα Loop (while(true)) στην Start Function τους
    και περιμένουν το thread που τα έφτοιαξε να τους σπάσει το loop (κάνει false το while).
    Μόλις τα Threads παιθάνουν το πρόγραμμα παίρνει τα Tables από το Dataset και τα ρίχνει σε 3 DataGridView Που έχω φτοιάξει για αυτό το σκοπό.
    Και τα 3 SQLConnections τρέχουν το ίδιο ConnectionString που το έχω φτοιάξει για Windows Authentication.

    Όταν το παραπάνω το τρέχω σε Debug(F5), δείχνει να δουλεύει κανονικά.
    Όταν το τρέχω σε Release(Ctrl-F5), με το που στέλνω την εντολή για να αρχίσουν να πεθαίνουν τα Threads (το κάνω με ένα button) το πρόγραμμα κολλάει.
    Από τον Performance Monitor τα threads φαίνονται να μην έχουν πεθάνει

    Τρέχω Sql Server 2008 Express σε VS 2008 Express, και Vista.

    Καμοιά ιδέα? Ευχαριστώ
  •  07-12-2008, 16:56 46761 σε απάντηση της 46752

    Απ: SCLConnection Μέσα από Threads με το ίδιο SQLConnectionString

    Μήπως να δοκιμάσεις να παίξεις με BackgroundWorker; Ο προγραμματισμός απευθείας με threads είναι αρκετά δύσκολος, κυρίως λόγω αυτού που αναφέρεις, ότι μπορεί να μην είναι ίδια η συμπεριφορά του προγράμματος κατά το debugging. Αν κατάλαβα καλά το σενάριο, προσπαθείς να γεμίσεις κάποιους πίνακες ταυτόχρονα, πράγμα που προσφέρεται για BackgroundWorker.


    Vir prudens non contra ventum mingit
  •  18-12-2008, 09:53 46973 σε απάντηση της 46761

    Απ: SCLConnection Μέσα από Threads με το ίδιο SQLConnectionString

    Τελικά με background worker δούλεψε. Βέβαια, αναρωτιέμαι μήπως έφταιγαν τα while loops μου που δεν είχαν κάποιο sleep ώστε να επιτρέπει στην CPU να κάνει καλό scheduling. Και με background worker είχα κάποια προβλήματα αλλά μόλις έβαλα κάποια sleeps όλα δούλεψαν ρολόι. φαινομενικά τουλάχιστο.
    Ευχαριστώ πολυ

  •  18-12-2008, 10:40 46974 σε απάντηση της 46973

    Απ: SCLConnection Μέσα από Threads με το ίδιο SQLConnectionString

    Τα sleep δεν χρειάζονται ποτέ, εκτός και αν υπάρχει bug. Η CPU δεν τα χρειάζεται για να κάνει scheduling. Αν χρειάζεσαι sleep, μάλλον κάπου υπάρχει blocking μεταξύ διαφορετικών threads. Αν, για παράδειγμα, χρησιμοποιείς όπως είπες, ένα global dataset ή αν πειράζεις άλλα global αντικείμενα, όπως  τα DataGridViews, έχεις θέμα blocking.

    Διαβάζοντας την αρχική περιγραφή σου πάντως σκέφτομαι ότι μάλλον δεν χρειάζεσαι ούτε threads ούτε BackgroundWorker. Φαίνεται ότι αυτό που θέλεις να κάνεις είναι να διαβάσεις πληροφορίες από τρία διαφορετικά connections και να μαζέψεις τα αποτελέσματα σε ένα σημείο? Τότε δεν χρειάζεσαι το while loop.

    Μία προσέγγιση είναι ένα delegate ο οποίος θα ανοίγει ένα connection και θα αποθηκεύει τα αποτελέσματα σε ένα datatable. Μετά, τρέχεις 3 φορές με BeginInvoke το ίδιο delegate με διαφορετικές παραμέτρους. Τα αποτελέσματα μπορείς να τα πάρεις με 2 διαφορετικούς τρόπους. Μπορείς να περάσεις ένα callback method στους Delegates το οποίο θα πάρει τα αποτελέσματα και θα τα γράψει στο κεντρικό dataset, ή μπορείς να περιμένεις να τελειώσουν και τα 3 threads με την WaitHandle.WaitAll για να πάρεις τότε τα αποτελέσματα. Την WaitAll θα την χρειαστείς έτσι κι αλλιώς για να γεμίσεις τα datagridviews. Βέβαια, αν κάθε DataGridView δείχνει τα αποτελέσματα ενός και μόνo query, μπορείς να κάνεις όλη τη δουλειά στα callbacks και δεν χρειάζεσαι το global Dataset.

    Αν όμως χρησιμοποιείς SQL Server έχεις μία ακόμα καλύτερη δυνατότητα, να εκτελέσεις τα queries ασύγχρονα. Η SqlCommand έχει τις BeginExecuteReader, BeginExecuteScalar, BeginExecuteNonQuery οι οποίες εκτελούν και αυτές ασύγχρονα μία εντολή και επιστρέφουν τα αποτελέσμαστα στις αντίστοιχες EndXXX. Όπως και με τα delegates, μπορείς να περάσεις ένα callback το οποίο θα κάνει update τα DataGridViews στο τέλος ή να τις περιμένεις όλες με την WaitHandle.WaitAll. Το μόνο που πρέπει να προσέξεις είναι ότι δεν μπορείς να εκτελέσεις πολλά ασύγχρονα SqlCommands πάνω στο ίδιο connection. Κάθε SqlCommand θα χρειαστεί το δικό του SqlConnection. Για παραδείγματα με όλους τους τρόπους κλήσης, δες το Performing Asynchronous Operations

    Το καλό με την τελευταία λύση είναι ότι είναι απλούστερη από όλες τις άλλες, απαιτεί λιγότερο κώδικα, δεν μπλέκει threads και αφήνει το ADO.NET να διαχειριστεί την ασύγχρονη επικοινωνία με τον SQL Server.


    Παναγιώτης Καναβός, Freelancer
    Twitter: http://www.twitter.com/pkanavos
  •  29-12-2008, 21:18 47279 σε απάντηση της 46974

    Απ: SQLConnection Μέσα από Threads με το ίδιο SQLConnectionString

    Παναγιώτη σε ευχαριστώ για την απάντηση αλλά στην προσπάθειά μου να μην μακρυγορήσω παράλλαξα κάπως αυτό που πραγματικά κάνω.
    Εξακολουθώ να έχω πρόβλημα.
    Βασικά, προσπαθώ να προσομοιώσω αισθητήρες. Κάθε αισθητήρας συνδέεται με έναν κεντρικό κόμβο(Intermediate).
    Δίνω το δικαίωμα και οι Intermediates να συνδέονται με έναν το πολύ Intermediate (Δέντρο με ένα ή δύο επίπεδα και φύλα τους κόμβους).
    Εικονικά, στον κεντρικό βρίσκεται η ΒΔ και σε τακτά χρονικά δεδομένα στέλνουν εκεί τα δεδομένα τους οι αισθητήρες. Για κάθε αισθητήρα έχω ένα table.
    Έχω υλοποιήσει τους κεντρικούς κόμβους σαν Backgroundworkers οι οποίοι δημιουργούν τους Sensors του group τους σαν Backgroundworkers επίσης.
    Κάθε intermediate έχει μια λίστα με κάθε Sensor που έχει δημιουργήσει και ανήκει στο Group του.
    Επίσης έχει και λίστα με του Intermediates που μπορεί να είναι συνδεδεμένοι με αυτόν

    Η συνολικά δουλεύει σωστά.
    Το πρόβλημα είναι όταν θέλω να τους σκοτώσω:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    public void Terminate()
    {
    //Σκότωσε τους Intermeditates σου
    foreach (KeyValuePair<string, Intermediate> interPair in IntermediateList)
    interPair.Value.Terminate();

    //Σκότωσε τους Sensors σου
    foreach (KeyValuePair<string, Sensor> sensorPair in SensorList)
    {
    sensorPair.Value.Terminate();
    }

    while (true)//Περιμένουμε μέχρι να πεθάνουν όλοι οι sensors
    {
    int liveCount = 0;
    for (int i = 0; i < SensorList.Values.Count; ++i)
    {
    if (SensorList.Values[ i ] .IsBusy)
    ++liveCount;
    }

    if (liveCount == 0)
    break;
    else
    Thread.Sleep(100);//Kοιμήσου λίγο και ξανάδοκίμασε
    }

    SensorList.Clear();
    TerminateLoop = true;//Εδώ τελειώνει το loop του Intermediate
    }
    Οι Sensor Και Intermediate κάνουν inherit την BackgroundWorker
    H Terminate απλά κάνει true μια μεταβλητή και σπάει ένα while loop που τρέχει στη Work function του Sensor

    Στην Γραμμή 18 Δεν καταφέρνω ποτέ να πάρω False.
    Στον debugger φαίνεται ποτέ να μην εκτελείται το event OnRunWorkerCompleted παρόλο που το event OnDoWork δείχνει να τερματίζει κανονικά.
    Γιατί συμβαίνει αυτό.
    Αν πάλι αφαιρέσω τον κώδικα όπου περιμένω να τερματίσουν οι BW, στο Performance monitor δεν φαίνεται να πεθαίνουν τα threads που δημιουργήθηκαν.
    Παρόλο που σταματούν οι ενημερώσεις της ΒΔ.






Προβολή Τροφοδοσίας RSS με μορφή XML
Με χρήση του Community Server (Commercial Edition), από την Telligent Systems