Tworzę aplikację wyświetlającą dane rynkowe i wykorzystującą je również w innych formach. Przechowuję dane rynkowe na mapie powiedz std::map<tickerId, StockData>. Podam jeden przykład wykorzystania tej mapy.

  1. sieć wysyła pakiet danych zawierający dane giełdowe w czasie t. updatePrice(tickerId, latestPrice)
  2. zaktualizować dane giełdowe na mapie. Teraz wiele wątków może uzyskiwać dostęp do danych i aktualizować je. Dlatego mapa musi być zablokowana dla operacji bezpiecznych dla wątków. Oto pierwsze pytanie, czy muszę blokować również podstawowe dane w celu aktualizacji?
  3. Istnieje wiele zastosowań nowych danych giełdowych, powiedzmy, że jest aktualizacja cen w IBM, a następnie muszę zaktualizować wartość IBM w moim portfelu. Jak również wyświetlać nowe dane na ekranie. I może być kilka innych równoczesnych zastosowań.updatePosition(tickerId, price) i updateStockScreen(tickerId, price). Również oddzielenie aktualizacji Gui od aktualizacji pozycji jest ważne, ponieważ GUI nie jest główną siłą aplikacji.
  4. Po prostu niepokoi mnie, jak zaimplementować tego typu projekt. Czytałem o projekcie modelu/widoku w QT, aby wyświetlić dane, ale jeśli wątek View czyta z tej samej mapy, musi być zablokowany. Prowadzi to do powolnego/nieefektywnego projektowania. Za każdym razem, gdy widok odczytuje model, model musi być zablokowany. Czy jest to preferowane w graficznych interfejsach użytkownika w czasie rzeczywistym?
  5. Podsumowując, przechowuję wiele różnych obiektów jako mapy. Obiekty są aktualizowane w czasie rzeczywistym. Muszę je zaktualizować, a następnie używać w różnych lokalizacjach. Byłoby super, gdyby ktoś dał mi mały przykład, jak realizować takie projekty.

Doceniane są również niektóre odniesienia do przydatnych książek.

Jestem nowy i staram się osiągnąć zbyt wiele z moją małą wiedzą, więc wybacz mi, jeśli zadałem głupie / źle sformułowane pytania.

Dzięki Shiv

13
shiv chawla 28 luty 2012, 20:01

2 odpowiedzi

Najlepsza odpowiedź

Brzmi koncepcyjnie tak, jakbyś chciał mieć model na jednym wątku, a widok na inny, do którego przyjrzałem się w pewnym momencie.

Jeśli tak... a twój model jest tylko do odczytu przez widżet widoku, to tak, musisz zablokować. Twierdzę, że takie postępowanie podważa elegancję „oddzielenia” zapewnianego przez separację modelu/widoku. Ale można to zmusić do pracy.

Jednak... jeśli Twój model jest do odczytu i zapisu w widoku, nie jest możliwe prawidłowe w ogóle ze względu na kolejkowany charakter okienek powiadomień. Oto archiwum konwersacji na liście dyskusyjnej, którą przeprowadziłem na liście dyskusyjnej qt-interest na ten temat:

http://blog.hostilefork.com/qt-model-view-different-threads/

„Krótka wersja jest taka, że ​​nie sądzę, aby model mógł
być modyfikowane w wątku bez GUI... niezależnie od tego, czy model jest
dane zostały zabezpieczone blokadami odczytu/zapisu. Jeśli to, co zbieram
jest poprawne, to prawdopodobnie Qt powinno mieć twierdzenie, że model i
jego widok ma takie samo powinowactwo wątku (wydaje się, że teraz tak nie jest)"

Potwierdził to kolejny test jednostkowy przeprowadzony przez programistę KDE.

Uważam, że najlepszym sposobem na obejście tego jest utrzymanie modelu i widoku w tym samym wątku i modyfikowanie modelu tylko w wątku GUI. Więc jeśli wątek roboczy chce to zmienić, powinien użyć sygnału.

To, czy pracownik musi zachować własną kopię danych, z których utworzono model (lub czy musi otrzymywać powiadomienia, aby były aktualne, gdy użytkownik zmieni model za pomocą widoku) zależy od aplikacji. Jeśli dobrze cię rozumiem, brzmi to tak, jakbyś prawdopodobnie mógł ujść na sucho, po prostu przesyłając aktualizacje przez sygnał/sloty i zapominając o nich na pracowniku...

13
HostileFork says dont trust SE 29 styczeń 2015, 21:35

Nauczyłem się dzisiaj innego potencjalnego problemu, na własnej skórze, nawet jeśli model był tylko do odczytu. Używam innego wątku do modyfikowania danych w modelu (właściwie mój program ma ponad 20 wątków i wszystkie grają ładnie), który następnie aktualizuje zegar Qt. Działa to bardzo dobrze, ale pojawił się problem, na który wpadłem, a mianowicie:

Nie możesz zablokować między rowCount/columnCount a data().

Qt działa sekwencyjnie, co oznacza, że ​​w ludzkim języku zapyta "jak duży jesteś", a następnie zapyta "jakie dane masz na tej pozycji", a te są podatne na zepsucie.

Rozważać:

int FilesQueue::rowCount(const QModelIndex &/*parent*/) const
{
    std::lock_guard<decltype(mainQueueMutex)> lg(mainQueueMutex);
    return filesQueue.size();
}
QVariant FilesQueue::data(const QModelIndex &index, int role) const
{
    std::lock_guard<decltype(mainQueueMutex)> lg(mainQueueMutex);
    if ( role == Qt::DisplayRole) {
        return filesQueue[index.row()]->getFilename();
    }
}

Qt wykona takie wywołania:

//...
obj->rowCount();
obj->data(...);
//...

Wszędzie miałem niepowodzenie asercji, ponieważ po prostu między rowCount() a data() był wątek, który zmieniał rozmiar danych! Zepsuło program. Tak się działo:

//...
obj->rowCount();
//another thread: filesQueue.erase(...)
obj->data(...);
//...

Moim rozwiązaniem problemu jest ponowne zweryfikowanie rozmiaru w metodzie data():

QVariant FilesQueue::data(const QModelIndex &index, int role) const
{
    std::lock_guard<decltype(mainQueueMutex)> lg(mainQueueMutex);
    //solution is here:
    if(static_cast<int>(filesQueue.size()) <= index.row())
        return QVariant();
    if ( role == Qt::DisplayRole) {
        return filesQueue[index.row()]->getFilename();
    }
}

I idą 3 godziny mojego życia, których już nigdy nie wrócę :-)

1
The Quantum Physicist 5 czerwiec 2017, 00:04