Hallo,
ich hab da mal eine blöde Frage!!!
Ich verwende in einem c++ Programm unter Linux mehrere Threads die
(fast) alle auf die gleiche Ressource zugreifen die mit einer Mutex
gegen (quasi) gleichzeitigen Zugriff gesichert ist.
Ein Thread jedoch benutzt die Ressource besonders stark so dass die
anderen nahezu nicht dran kommen, denn immer wenn sie Rechenzeit
bekommen ist die Ressource durch den einen noch gesperrt.
Meine Frage:
Gibt es irgendeine Möglichkeit den Scheduler zu einem bestimmten
Zeitpunkt, z.B. nach "pthread_mutex_unlock", zu veranlassen einen
"context switch" durchzuführen ???.
Momentan behelfe ich mich damit dass ich immer nach
"pthread_mutex_unlock" eine Wartezeit einfüge innerhalb der bestimmt ein
"context switch" erfolgt.
Das ist natürlich keine schöne Sache.
Gruss Stefan
Hallo Μαtthias W.
das war jetzt ein sehr guter Hinweis, ich hab zwar jetzt noch nicht
> sicher_yield()
gefunden aber
sched_yield(void);
denke ich tuts auch!
Danke, sehr gut !!!
Stefan schrieb:> Momentan behelfe ich mich damit dass ich immer nach> "pthread_mutex_unlock" eine Wartezeit einfüge innerhalb der bestimmt ein> "context switch" erfolgt.
Da der ja gleich zu Beginn der Wartezeit passiert, kannst du auch
einfach eine Wartezeit von 0 angeben.
Μαtthias W. schrieb:> sicher_yield() sollte das sein was du suchst.
Du meinstest vermutlich sched_yield().
Stefan schrieb:> Hallo,> ich hab da mal eine blöde Frage!!!>> Ich verwende in einem c++ Programm unter Linux mehrere Threads die> (fast) alle auf die gleiche Ressource zugreifen die mit einer Mutex> gegen (quasi) gleichzeitigen Zugriff gesichert ist.
Quasi? Nimm eine Multicore-CPU oder ein SMP-System und da ist nix
quasi...
Übrigens auch der einzige Weg um eine halbwegs realistische Chance zu
haben jemals Fehler im Locking aufzudecken. Multithreading mit
Single-Core ist wie Gruppensex allein... ;-)
> Ein Thread jedoch benutzt die Ressource besonders stark so dass die> anderen nahezu nicht dran kommen, denn immer wenn sie Rechenzeit> bekommen ist die Ressource durch den einen noch gesperrt.
Dann ist da etwas falsch designed. Meiner Meinung nach. Was soll MT in
so einem Fall bringen?
Wie man es trotzdem halbwegs zum Laufen bekommt ist schon beantwortet
worden.
Jasch schrieb:> Dann ist da etwas falsch designed. Meiner Meinung nach. Was soll MT in> so einem Fall bringen?
Ja, könnte man meinen!
Aber in meinem Fall greift die besagte Methode auf eine Hardware-Einheit
zu und kann desshalb nicht "reentrant" sein so sehr ich das auch möchte.
Also muss ich den Zugriff mit Mutex serialisieren (einer nach dem
anderen) und da hilft auch keine
Jasch schrieb:> Multicore-CPU oder ein SMP-System
Dies gilt im übrigen für alle Komponenten die in einem Rechner nur
einmal vorhanden sind !!!
Häufig macht man sich die Sache ganz einfach und sperrt sie mit
open/close gleich für alle übrigen Nutzer. Das geht in meinem Fall
gleich gar nicht.
Stefan schrieb:> Ein Thread jedoch benutzt die Ressource besonders stark so dass die> anderen nahezu nicht dran kommen, denn immer wenn sie Rechenzeit> bekommen ist die Ressource durch den einen noch gesperrt.
Dann geht es wohl eher um Prioritäten und Rechenzeit.
Du müßtest die Priorität des Threads herunterstufen, nachdem er die
Resource gehabt hat.
Auch wenn Du mit sched_yield() die CPU abgibst, aber der Thread
weiterhin die höchste Priorität hat, wird er weiterrechnen.
Das erwähnte sched_yield kann nützen wenn die Threads alle die gleiche
Priorität haben.
Wenn es deine Applikation erlaubt, kannst Du den Thread auch für ein
paar ms schlafen legen, dann kommen die anderen zum Zug.
Du müsstest einmal analysieren, warum ein Thread die CPU monopolisiert.
- Hat er höhere Priorität als die anderen
- Ist er rechenintensiver als die anderen, sodass er länger laufen kann
bis zum nächsten Sys-Call
Ich versteht das Problem nicht, die anderen Thread warten doch an der
Stelle wo sie die Resource brauchen, sobald sie von dem anderne Thread
freigegeben wird kommen sie dran. Der andere Thread muss doch doch auch
wieder hinten anstellen.
Peter II schrieb:> Der andere Thread muss doch doch auch> wieder hinten anstellen.
Nicht wenn er immer noch der aktive Thread ist und ein paar µs später
die Ressource wieder allokiert.
Das würde nur funktionieren wenn bei jeder Freigabe der Mutex
automatisch ein Contextswitch zu dem nächsten Prozess stattfindet, aber
das (ich weiss das jetzt nicht genau) dürfte eigentlich nicht der Fall
sein.
Und ich denke auch nicht daß ein Mutex eine genaue Reihenfolge einhält
weil das ja nicht mit dem Scheduler für die Threads und Prozesse zu
synchronisieren ist.
Udo Schmitt schrieb:> wenn bei jeder Freigabe der Mutex> automatisch ein Contextswitch zu dem nächsten Prozess stattfindet,
Solche Details sind sicher implementierungsabhängig und hängen vom
verwendeten Betriebsystem ab.
Im Normalfall erfolgt ein Contex-Switch nur, wenn ein höher
priorisierter Thread auf die Mutex wartet oder sonst irgendwie die
Zeitscheibe für den Thread aufgebraucht ist.
Die Freigabe einer Mutex ist ja auch kein Grund den Thread zu
unterbrechen, schließlich hat es das selbe Anrecht auf Rechenzeit wie
die anderen, wartenden Threads und ein Context-Switch verschwendet nur
CPU-Leistung.
Klaus Falser schrieb:> Die Freigabe einer Mutex ist ja auch kein Grund den Thread zu> unterbrechen, schließlich hat es das selbe Anrecht auf Rechenzeit wie> die anderen, wartenden Threads und ein Context-Switch verschwendet nur> CPU-Leistung.
Genau das meine ich. Wenn der eine Prozess in 95% seiner Laufzeit die
Ressource über den Mutex blockiert, dann ist die Wahrscheinlichkeit daß
der Mutex frei ist wenn der nächste Prozess drankommt nur 1/20. Es ist
irrig anzunehmen, daß alle auf den Mutex wartenden Prozesse schön der
Reihe nach drankommen. Sie kriegen eine Zeitscheibe und wenn der Mutex
frei ist kriegen sie ihn, ansonsten wird zum nächsten Prozess/Thread
abgegeben.
Insofern wäre es ein Lösungsansatz nach jedem Freigeben des Mutex in dem
Prozess der die Ressource so oft belegt ein yield() einzubauen, oder
auch nur bei jedem 2. oder 5. freigeben.
Ein anderer Ansatz wäre, einen eigenen Thread zu schreiben, der alle
Anfragen auf die Ressource kanalisiert und ggf. 'gerechter' verteilt.
Peter II schrieb:> Ich versteht das Problem nicht, die anderen Thread warten doch an der> Stelle wo sie die Resource brauchen, sobald sie von dem anderne Thread> freigegeben wird kommen sie dran. Der andere Thread muss doch doch auch> wieder hinten anstellen.
genau dieses "hintenanstellen" will ich ja erreichen, aber es ist leider
so dass sich der eine Thread die Ressource wieder schnappt bevor durch
einen "context-switch" einer der anderen dran ist!!!
könnte man das nicht mit einem 2. Mutex lösen?
Ich habe jetzt nicht weiter nachgedacht.
1. Thread 1.Mutex nehmen
1. Thread 2.Mutex nehmen
1. Thread 1.Mutex freigeben
1. Thread Arbeiten
1. Thread 2.Mutex freigeben
wenn jetzt ein 2. Thread kommt, dann hat er ja den 1.Mutex schon, damit
kommt dann Thread 1 nicht weiter und beim contextwechsel ist dann Thread
2 dran.
Tut das Problem bitte nicht verkomplizieren !!!
Es reicht wenn ich dafür sorge dass immer dann ein "context switch"
durchgeführt wird wenn die Ressource frei ist.
Bisher hatte ich das mit einer Wartezeit gelöst (ist aber unschön,
desshalb die Frage).
pthread_yield() und/oder sched_yield() sind genau die richtigen
Werkzeuge um das "hintenanstellen" zu erzwingen (bei gleicher Priorität)
Stefan schrieb:> Hallo Μαtthias W.>>> das war jetzt ein sehr guter Hinweis, ich hab zwar jetzt noch nicht>> sicher_yield()> gefunden aber>> sched_yield(void);>> denke ich tuts auch!
Das war auch gemeint. Die Autokorrektur in Android hat leider
zugeschlagen.
Matthias
Stefan schrieb:> pthread_yield() und/oder sched_yield() sind genau die richtigen> Werkzeuge um das "hintenanstellen" zu erzwingen (bei gleicher Priorität)
Zumindest dass die anderen Prozesse dann drankommen wenn die Ressource
frei ist.
Falls allerdings dein Prozess der die Ressource oft braucht sie ständig
alloziert und wieder freigibt dann würde er auch sehr oft yielden was
dazu führt daß er immer weniger Rechenzeit hat weil er seine Zeitscheibe
immer gleich wieder abgibt.
Wie gesagt, meine Idee wäre den Zugriff zu der Ressource gezielt in
einem eigenen Thread zu steuern, aber das war ein Schuss ins blaue da
ich nicht weiß was du tun willst. Peter IIs Idee habe ich jetzt ehrlich
gesagt noch nicht durchgedacht.
Nachtrag:
Peter II schrieb:> 1. Thread 1.Mutex nehmen> 1. Thread 2.Mutex nehmen> 1. Thread 1.Mutex freigeben> 1. Thread Arbeiten> 1. Thread 2.Mutex freigeben
könnte funktionieren, wenn das "Thread Arbeiten" wensentlich länger
dauert als das allozieren der Mutexe, wenn der eine Thread allerdings
sehr oft die Ressource für sehr kurze Zeit alloziert bringt es nicht so
viel.
Allerdings müsste man nochmal gründlich über Dead Locks nachdenken, auf
die Schnelle sehe ich aber nix problematisches.
Was macht den dein Thread wenn er den Mutex nicht kriegt? Kann er
nebenbei noch was anderes machen? Und wie lange benötigt er die
geschützte Resource, was kommt dann?
Stefan schrieb:> Häufig macht man sich die Sache ganz einfach und sperrt sie mit> open/close gleich für alle übrigen Nutzer.
Die andere Variante ist, daß grundsätzlich nur ein Thread direkt auf die
Ressource zugreift und Zugriffsanforderungen von den anderen Threads
annimmt und koordiniert. Die können dann weitermachen, solange der
Zugriffsthread auf die Hardware wartet.
Klaus Falser schrieb:> Im Normalfall erfolgt ein Contex-Switch nur, wenn ein höher> priorisierter Thread auf die Mutex wartet
Oder auf irgendwas anderes, sei es ein File/Device, ein Socket,
Semaphore oder auch einfach bei einem sleep, wo er nur auf das Ablaufen
der Zeit wartet.
> Die Freigabe einer Mutex ist ja auch kein Grund den Thread zu> unterbrechen,
Doch, denn höherpriore Threads könnten gerade auf die Freigabe warten.
> schließlich hat es das selbe Anrecht auf Rechenzeit wie die anderen,
Es gibt Prioritäten, und höherpriore Threads haben auch ein höheres
Anrecht.
Stefan schrieb:> Jasch schrieb:>> Dann ist da etwas falsch designed. Meiner Meinung nach. Was soll MT in>> so einem Fall bringen?>> Ja, könnte man meinen!> Aber in meinem Fall greift die besagte Methode auf eine Hardware-Einheit> zu und kann desshalb nicht "reentrant" sein so sehr ich das auch möchte.
OK, klar. Wobei Reentranz etwas anderes meint, Deine Methode ist
ziemlich sicher reentrant.
> Also muss ich den Zugriff mit Mutex serialisieren (einer nach dem> anderen) und da hilft auch keine
Nun ja, wieso sollen überhaupt mehrere Threads direkt drauf zugreifen,
bringt doch offensichtlich keinen Vorteil?
> Jasch schrieb:>> Multicore-CPU oder ein SMP-System>> Dies gilt im übrigen für alle Komponenten die in einem Rechner nur> einmal vorhanden sind !!!
Klar. Sollte übrigens nicht etwa "helfen" - sondern vor der Vorstellung
"quasi-gleichzeitig" warnen, weil das eben heutzutage oft ganz real
gleichzeitig ist.
Wobei man auf nur einmal vorhandene Komponenten auch nicht MT zugreift -
genau weil es nix bringt. Wie soll man sich z.B einen MT-Zugriff auf die
Tastatur vorstellen, jeder Thread bekommt mal irgendeinen Tastendruck
mit?
Da müsstest Du wohl mal genauer beschreiben was Du eigentlich tust -
dann kann man es auch verstehen und bessere Hinweise geben.
> Häufig macht man sich die Sache ganz einfach und sperrt sie mit> open/close gleich für alle übrigen Nutzer. Das geht in meinem Fall> gleich gar nicht.
Rolf Magnus hat geschrieben wie man sowas macht.
Das impliziert natürlich recht schnell etwas wie ein Betriebssystem mit
Treibern, Queues, Blah, usw. usf.