Hallo leute,
eigentlich wollte ich mich nur mal mit Layered Windows unter C# versuchen und auf einmal komme ich zu einem "deadlock", der für mich absolut unerklärlich ist.
void Form1_Click(object sender, System.EventArgs e) {
Bitmap b = new Bitmap(300, 400, PixelFormat.Format32bppArgb);
Graphics g = Graphics.FromImage(b);
using (Brush RedTransparentBrush = new SolidBrush(Color.FromArgb(100, Color.DarkRed)))
g.FillRectangle(RedTransparentBrush, 0, 0, b.Width, b.Height);
lock (_updateWindowLock) // BAM! blockiert das gesamte Programm!
SetBitmap(b);
}
private void FadeThreadMethod(object objStartArgs) {
int[] startArgs = (int[])objStartArgs;
lock (_updateWindowLock) {
if (startArgs[0] < startArgs[1]) { // Fade in!
for (int op = startArgs[0]; op < startArgs[1]; op += startArgs[2]) {
Invoke(new MethodInvoker(delegate() { SetOpacity((byte)op); }));
Thread.Sleep(startArgs[3] / (startArgs[1] - startArgs[0]) * startArgs[2]);
}
} else if (startArgs[0] > startArgs[1]) { // Fade out!
for (int op = startArgs[0]; op > startArgs[1]; op -= startArgs[2]) {
Invoke(new MethodInvoker(delegate() { SetOpacity((byte)op); }));
Thread.Sleep(startArgs[3] / (startArgs[0] - startArgs[1]) * startArgs[2]);
}
}
MessageBox.Show("fertig");
}
}
Sobald ich klicke, während er FadeIn macht, endet dies in einer Blockade der FadeThreadMethod (die parallel läuft).
Ich wollte nur nicht, das während des FadeIns die farbe geändert werden kann (sei dahingestellt ob das sinnvoll ist).
Ich habe Monitor.TryEnter mit 2000 ms timeout versucht:
Programm blockiert 2 sekunden, und fade rennt dann weiter!
Rot wird der hintergrund allerdings nur, wenn ich das form NACH dem faden anklicke.
Bitte kein kommentar zu den fehlenden casts bei der division, das ist jetzt nebensächlich 😃
danke für deine schnelle antwort!
naja erstens gehts mir mal um das threading, jetzt will ichs wissen 😄
und zweitens, animatewindow geht afaik nicht bei "per-pixel-alpha"-layered windows, oder?
ich sehe keinen Aufruf der Methode FadeThreadMethod, wo und wie wird sie aufgefuren?
Form1_Click scheint unkomplett zu sein
Es gibt
lock (_updateWindowLock) // BAM! blockiert das gesamte Programm!
aber es gibt kein unlock, wie hier
lock(xxxx)
{
sicheres code
}
Grüße
Pawel
lock(_updatewindowLock) EINE_ANWEISUNG;
beendet den block nach der anweisung, wodurch monitor.Exit aufgerufen wird.
FadeThreadMethod wird natürlich im Konstruktor über den Thread mit .Start() aufgerufen.
Mach mal aus den beiden Invokes, jeweils ein BeginInvoke.
Invoke wartet ja bekanntlich darauf, dass der GUI Thread bereit ist eine Aktion auszuführen und führt die die Aktion dann im GUI Thread und warted bis diese fertig ist.
Nun ist aber dein GUI Thread Blockiert und und wartet darauf das die Thread-Methode den Lock aufhebt. Ergo Deadlock.
Irgendwo gabs hier ma
omg...
danke vielmals..
mit begininvoke gehts bei näherer überlegung genau so wenig (von der anzeige her) aber der deadlock is weg!
*verbeuge*
Sodala, weiter im Text..
Habe das ganze jetzt so umgeschrieben, blockiert aber ebenfalls wieder (siehe comment)
void Form1_Click(object sender, System.EventArgs e) {
Bitmap b = new Bitmap(300, 400, PixelFormat.Format32bppArgb);
Graphics g = Graphics.FromImage(b);
using (Brush RedTransparentBrush = new SolidBrush(Color.FromArgb(100, Color.DarkRed)))
g.FillRectangle(RedTransparentBrush, 0, 0, b.Width, b.Height);
ThreadInvoke(delegate() {
lock (_updateWindowLock) // blockert gesamte Anwendung
SetBitmap(b);
});
}
private void FadeThreadMethod(object objStartArgs) {
int[] startArgs = (int[])objStartArgs;
lock (_updateWindowLock) {
if (startArgs[0] < startArgs[1]) { // Fade in!
for (int op = startArgs[0]; op < startArgs[1]; op += startArgs[2]) {
Invoke(new MethodInvoker(delegate() { SetOpacity((byte)op); }));
Thread.Sleep(startArgs[3] / (startArgs[1] - startArgs[0]) * startArgs[2]);
}
} else if (startArgs[0] > startArgs[1]) { // Fade out!
for (int op = startArgs[0]; op > startArgs[1]; op -= startArgs[2]) {
Invoke(new MethodInvoker(delegate() { SetOpacity((byte)op); }));
Thread.Sleep(startArgs[3] / (startArgs[0] - startArgs[1]) * startArgs[2]);
}
}
}
}
private void ThreadInvoke(MethodInvoker d) {
Thread t = new Thread(delegate() { Invoke(d); });
t.Start();
}
Meiner Ansicht nach müsste jetzt der GUI Thread frei sein, oder?#
edit: man bin ich dumm, klar das wenn das lock innerhalb Invoke aufgerufen wird, das selbe rauskommt 😃
Lösung:
private void ThreadInvoke(object LockObject, MethodInvoker d) {
Thread t = new Thread(delegate() { lock(LockObject() Invoke(d); });
t.Start();
}
und eben den aufruf anpassen (ohne lock im delegate)
kann geschlossen werden =)