Entwickler-Ecke

Sonstiges (.NET) - Backgroundworker - Blockiert GUI Thread


meisse - Fr 17.06.11 15:20
Titel: Backgroundworker - Blockiert GUI Thread
Hallo zusammen

Ich verwende den BackgroundWorker, um grosse Dateien (>100MB) über das Netzwerk zu beziehen und diese dann abzuspeichern. Gleichzeitig wird habe ich eine Progressbar
welche den Status des Files anzeigt. Leider wird aber während dem speichern das GUI und die Progressbar massiv blockiert. Die Daten werden folgendermassen bezogen:



C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
if (waveformDataSource.HasRawData()) {
                                        int[] data = waveformDataSource.GetRawData(blk, startSample + offset, doNow);

                                        if (red.ReductionInfo.Type == DataReductionType.None || red.ReductionInfo.Factor == 1) {
                                            block.AppendRawData(data, 0, doNow);
                                        } else {
                                            List<int> reduced = red.Reduce(data);
                                            block.AppendRawData(reduced.ToArray(), 0, reduced.Count);
                                        }
                                    }



Der Aufruf von waveformDataSource.GetRawData() blockiert regelrecht den Gesamtbetrieb. Die Methode GetRawData greift auf eine C++ definierte Methode zurück welche folgendermassen definiert ist:



C#-Quelltext
1:
2:
3:
4:
5:
[DllImport(dllName)]
            public static extern ErrorCode TPC_GetRawData(int deviceIx, int boardAddress, int inputNumber,
                                                          int blockNumber,
                                                          int measurementNumber, UInt64 dataStart, int dataLength,
                                                          IntPtr /*(Int32*)*/ data);



Hat dies etwas mit dem Blockieren des GUI Threads zutun oder muss ich ganz wo anders suchen? Was für Zustände können den GUI THread noch blockieren? Muss dieser Methodenaufruf mit BeginInvoke aufgerufen werden damit dieser in einem separaten Thread läuft??

Mit freundlichen Grüssen


Christoph1972 - Fr 17.06.11 15:30

Bist du dir sicher das du den BW korrekt verwendest?


meisse - Fr 17.06.11 15:45

Folgendermassen wird der Backgroundworker verwendet:


C#-Quelltext
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:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
BackgroundWorker _worker;

public void RunAsyncTpc5Writer(string filename, DataReductionInfo redInfo, DataReductionInfo redInfoECREvents) {
            _worker = new BackgroundWorker();
            _worker.WorkerReportsProgress = true;
            _worker.WorkerSupportsCancellation = true;

            _CurrentDoFilename = filename;
            _CurrentRedInfo = redInfo;
            _CurrentRedInfoECREvents = redInfoECREvents;

            _worker.DoWork += new DoWorkEventHandler(_worker_WriteTpc5Async);
            _worker.RunWorkerAsync();
        }


        private void _worker_WriteTpc5Async(object sender, DoWorkEventArgs e) {
            WriteTpc5Blocks(_CurrentDoFilename, _CurrentRedInfo, _CurrentRedInfoECREvents, null);
        }


private void WriteTpc5Blocks(string filename, DataReductionInfo redInfo, DataReductionInfo redInfoECREvents, BackgroundWorker worker) {
            //using (Tpc5File f = new Tpc5File(filename, FileMode.Create, FileAccess.ReadWrite)) {
            try {
.......

while (toGo > 0) {
                                    int doNow = (int)Math.Min(toGo, 1 * 1048576); // 1048576

                                    if (waveformDataSource.HasRawData()) {
                                        int[] data = inputSource.GetRawData(blk, startSample + offset, doNow);
                                        //int[] data = waveformDataSource.GetRawData(blk, startSample + offset, doNow);

                                        if (red.ReductionInfo.Type == DataReductionType.None || red.ReductionInfo.Factor == 1) {
                                            block.AppendRawData(data, 0, doNow);
                                        } else {
                                            List<int> reduced = red.Reduce(data);
                                            block.AppendRawData(reduced.ToArray(), 0, reduced.Count);
                                        }
............
}
}


Es wurde noch keine RunWorkerCompleted & ProgressChanged methoden implementiert.


Christoph1972 - Fr 17.06.11 15:58

user profile iconmeisse hat folgendes geschrieben Zum zitierten Posting springen:

Es wurde noch keine RunWorkerCompleted & ProgressChanged methoden implementiert.



Und wie soll das dann mit deiner Progressbar funktionieren ?


meisse - Fr 17.06.11 15:58

Ich habe nun folgendes programmier:


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
if (waveformDataSource.HasRawData()) {
                                        int[] data = waveformDataSource.GetRawData(blk, startSample + offset, doNow);
                                        Thread.Sleep(100000);
                                        

                                        if (red.ReductionInfo.Type == DataReductionType.None || red.ReductionInfo.Factor == 1) {
                                            block.AppendRawData(data, 0, doNow);
                                        } else {
                                            List<int> reduced = red.Reduce(data);
                                            block.AppendRawData(reduced.ToArray(), 0, reduced.Count);
                                        }
                                    }


Nach dem die Daten via waveformDataSource.GetRawData() bezogen wurden (Es wird jeweils 1MB Daten Pro schleifendurchgang bezogen), pausiere ich den
BackgroundWorker für 100 Sekunden. Das Gui ist in dieser Zeit ohne Probleme zu bedienen. Also muss es irgendeinen Grund geben, warum der Aufruf
waveformDataSource.GetRawData() den GUI Thread so starch blockiert. Ich habe den BackgroundWorker schon an anderen Orten erfolgreich implementiert ohne
dass ich das GUI blockiert habe.


meisse - Fr 17.06.11 16:03

Natürlich wird so die progressbar nicht funktionieren. Dies habe ich noch nicht implementiert weil dieses Problem (GUI not resposinve) zum Vorschein gekommen ist und die Progressbar zum jetztigen Zeitpunkt noch nicht relevant ist.


Kha - Fr 17.06.11 16:38

Das hört sich schon sehr merkwürdig an. Die höheren Versionen von VS2010 bieten aber einen Multithreading-Profiler, der dir genauer sagen sollte, womit sich der GUI-Thread da beschäftigt.


meisse - Fr 17.06.11 16:45

Ok danke für den Hinweis. Ich werde mich mal damit befassen. Besitze VS 2010 Professional. Wenn ich weitere Hinweise habe oder Lösungen werde ich mich wieder melden.