(fast) gleichzeitig Elemente Vectoren hinzufügen
-
314159265358979 schrieb:
cooky451 schrieb:
static std::mutex m;Und wer garantiert dir, dass die Erstellung des Mutex atomar ist?
muss sie nicht. gcc kann es auf jeden fall; msvc weiß ich gerade nicht, sollte aber auch...
-
314159265358979 schrieb:
cooky451 schrieb:
static std::mutex m;Und wer garantiert dir, dass die Erstellung des Mutex atomar ist?
Ob die Erstellung der Mutex atomar ist oder nicht, ist vollkommen egal.
Wenn nämlich die Chance besteht dass man auf die Mutex zugreift während diese gerade initialisiert wird, dann besteht genauso auch die Chance dass man auf die Mutex zugreift bevor überhaupt angefangen wurde sie zu initialisieren.
Ob die noch-nicht-angefangene Initialisierung atomar ist oder nicht spielt dann überhaupt keine Rolle mehr.
-
Und wenn der Mutex 2 mal initialisiert wird und dabei Daten des zuerst "fertig" erstellten Mutex überschrieben werden? :p
-
Insgesamt war die Idee eines lokalen statischen mutex eigentlich ziemlicher Schwachsinn, wenn man sich nur mal überlegt, wie man das erweitern möchte. Da hat man dann ein atomic_pop_front() und die bekommt wieder ein extra mutex? Doppelt aua. Eine safe_vector* Klasse ist wohl doch die einzig passable Lösung. (Abgesehen natürlich von std::future mit std::async, was ich bevorzugen würde wenn es geht.)
* Und dann am besten auch gleich nicht vector nennen, sondern sondern nach etwas was besser passt. (Und dann auch ein verringertes Interface anbieten.) Sonst kommt noch jemand auf die Idee Algorithmen mit dem Vektor aufzurufen.
-
314159265358979 schrieb:
Und wenn der Mutex 2 mal initialisiert wird und dabei Daten des zuerst "fertig" erstellten Mutex überschrieben werden? :p
Ach, das ist ein function-local static.
Nachdem du den Kontext in deinem Zitat unterschlagen hast, war das nicht ersichtlich, und ich dachte das Ding wäre global.Ja, function-local statics sind in pre-C++ 11 Zeiten ein potentielles thread-safety Problem.
-
Hallo,
ich habe noch ein neues Problem in Anlehnung an diese Problematik.
Ich starte zwei Threads, die jeweils einen Pointer auf das gleiche Objekt erhalten. Um sicherzugehen, habe ich mal im ganzen Thread, außer während eines Download, Mutex gelocked.
Hier ein Auszug der Funktion, die als Thread ausgeführt wird:
//MUTEX BEGIN if (pthread_mutex_lock(&mutex) != 0){cout << "[FATAL] COULD NOT LOCK MUTEX";} //irgendwelcher thread-unsicherer Code if (blabla){ //irgendwelcher thread-unsicherer Code if (pthread_mutex_unlock(&mutex) != 0){cout << "[FATAL] COULD NOT UNLOCK MUTEX";} //MUTEX END etc_lib().download_file(url, localfile); //MUTEX BEGIN if (pthread_mutex_lock(&mutex) != 0){cout << "[FATAL] COULD NOT LOCK MUTEX";} } try{ string s = ArticleView->get_settingsreader()->get_value("temp_download_directory"); s += ArticleView->get_article()->hash + ".htm"; article* a = ArticleView->get_article(); ...Ich sehe, dass der zweite Thread erst startet (bzw. in den unsicheren Code geht), wenn im ersten Thread der Download beginnt. Beide Downloads starten dann. Wenn ein Thread mit dem Download fertig ist, geht er weiter in den try Block, der andere Thread wartet. So sollte das ja auch sein.
Dummerweise stürzt der Programm immer in während der ersten beiden Zeilen (meist in der ersten) vom try-Block ab. An den Methoden kann es nicht liegen, ohne Parallelisierung klappt das. Allerdings nutzen beide Threads den gleichen Pointer ArticleView und damit auch das gleiche Objekt settingsreader. Die Methode settingsreader()->get_value() sucht in einem Member-Vector nach dem übergebenden Parameter.
Da beide Threads vor dem Download die Objekte genutzt haben, kann es sein, dass der eine Thread das Objekt noch irgendwie blockiert oder nutzt?
Habe ich da etwas grundsätzlich falsch verstanden?
Ich danke euch schonmal.
-
hat niemand eine Idee?
-
Doch, debugger nehmen und die !genaue! Stelle im Code finden. Ich tippe auf eine Dereferenzierung eines Nullpointers.
-
Meist bricht er in der ersten Zeile des try-Blocks ab. Das ist die Methode:
string settings_reader::get_value(string setting_name) { for (int i = 0; i < m_setting.size(); i++) // m_settings ist ein vector<string> if (m_setting[i] == setting_name){ // Abbruch return m_values[i]; } return "nA"; }Beim Debuggen brach er einmal im zweiten Durchlauf, einmal beim ersten Durchlauf ab. Die Fehlermeldung(en): manchmal "*** Abgestürzt mit Rückgabewert: 0 ", manchmal " Programm hat Signal SIGSEGV (Segmentation fault) empfangen ***".
Auf dieses Objekt haben ja beide Threads Zugriff, bzw. vorher auch schon genutzt. Kann es da sein, dass der eine Thread, der eigentlich wartet, das Objekt, bzw. dessen vector noch blockiert?
-
Ist i innerhalb der Größe des vectors?
-
Wie ich schon gesagt habe, kann es nicht an der Methode selber liegen, da mit einem Thread alles läuft, der Fehler aber erst bei zwei gleichzeitigen Threads kommt. Die Threads selber ändern die Objekte nicht. (Mir fällt dabei auf, dass ich die Methode nicht als const definiert habe, ist gerade nachgeholt worden).
edit: hier stand Mist. Beide Vektoren haben die gleiche Größe, das ist garantiert.
-
Mach doch einfach mal ein assert(m_setting.size() == m_values.size() ) an den Anfang.
-
Ich habe mir die Größe der Vektoren auch explizit ausgeben lassen, beide sind immer gleich.
-
Was passiert den, wenn du in der Funktion einfach immer "nA" zurück gibst?
-
Das ist schwierig, weil die Methode schon vorher öfters benutzt wird. Ich habe aber mal die Zeile auskommentiert und stattdessen explizit einen Wert angegeben:
// string s = ArticleView->get_settingsreader()->get_value("temp_download_directory"); string s = "/tmp/"; s += ArticleView->get_article()->hash + ".htm"; article* a = ArticleView->get_article();Das Programm bricht dann bei der nachfolgenden Zeile, bzw. beim Aufruf von ArticleView->get_article()->hash. Auch ArticleView ist ein Pointer, den beide Threads nutzen. Auch hier bricht er nur ab, wenn ich das mit zwei Threads gleichzeitig ausführe.
-
ist bei if(blablabla) blablabla true ?
-
Ja, das ist ein länglicher Ausdruck, der wahr ist, ansonsten würde ich doch gar nicht dahin kommen?
-
Achso, jetzt habe ich das gesehen
Kannst du mal die ganze Funktion zeigen?
-
ok, hier zumindest der Teil bis zum Programmabsturz:
void* thread_download_parse_arcticlepage (void* arg){ article_view* ArticleView = (article_view*) arg; //MUTEX BEGIN if (pthread_mutex_lock(&mutex) != 0){cout << "[FATAL] COULD NOT LOCK MUTEX";} if (!ArticleView->get_article()->parsed_article_site){ ArticleView->get_StatusDisplay()->add_text ("Angebotsseite downloaden und parsen"); string url, localfile; url = ArticleView->get_article()->url_to_auction; localfile = ArticleView->get_settingsreader()->get_value("temp_download_directory") + ArticleView->get_article()->hash + ".htm"; int seconds_since_last_access = etc_lib().seconds_since_last_file_access(localfile); if (seconds_since_last_access < 0 || (double) seconds_since_last_access > ArticleView->get_settingsreader()->get_dvalue("updating_article_site") * 60){ cout << "unlock mutex for download"<<endl; if (pthread_mutex_unlock(&mutex) != 0){cout << "[FATAL] COULD NOT UNLOCK MUTEX";} //MUTEX END cout << "start download " << url<<endl; etc_lib().download_file(url, localfile); cout << "finished download " << url<<endl; //MUTEX BEGIN if (pthread_mutex_lock(&mutex) != 0){cout << "[FATAL] COULD NOT LOCK MUTEX";} } try{ string s = ArticleView->get_settingsreader()->get_value("temp_download_directory"); s += ArticleView->get_article()->hash + ".htm"; article* a = ArticleView->get_article(); ArticleView->get_parser()->parse_article_site(s, a); ArticleView->get_article()->url_to_localimage = ArticleView->get_settingsreader()->get_value("temp_download_directory") + ArticleView->get_article()->hash + ".jpg"; } catch (eParseException &Exception){ std::cout << "[PARSING ERROR] " << Exception.get_errmsg() << endl; } ...Wie gesagt wartet einer von beiden Threads (zumindest habe ich das mit "cout-Debuggen" festgestellt) nach dem Download, der erste der fertig ist macht dann weiter und stürzt im try-Block ab.
-
Der Fehler liegt bestimmt irgendwo in ArticleView.
Btw. als Tipp: Typen werden meist gross geschrieben und Variablen klein. Darueber hinaus ist dein Quelltext eher von schlechter Qualitaet.