Permalänk

cross thread - c#

Har lite problem med en funktion som försöker ändra i en annan tråd än den tråd funktionen körs i.

here's the code:

using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Timers; namespace snake { public partial class Form1 : Form { public static int dir = 1, x, y; public static Point p; public Form1() { InitializeComponent(); p = blacksq.Location; } private void Form1_Load(object sender, EventArgs e) { Timer(); } public void Timer() { System.Timers.Timer aTimer = new System.Timers.Timer(); aTimer.Elapsed += new ElapsedEventHandler(onTimedEvent); // time in ms = 4 moves per sec aTimer.Interval = 250; aTimer.Enabled = true; MessageBox.Show("timer started"); } //onTimedEvent - move snake public void onTimedEvent(object source, ElapsedEventArgs e) { Point p = blacksq.Location; // x = east/west // y = north/south if (dir == 0) { //move north p.Y += 5; //blacksq.Location = p; Location = p; } else if (dir == 1) { //move east p.X += 5; Location = p; } else if (dir == 2) { //move south p.Y -= 5; Location = p; } else if (dir == 3) { //move west p.X -= 5; Location = p; }; } private void Form1_KeyDown(object sender, KeyEventArgs e) { // on keypress (arrows) change direction if (e.KeyCode == Keys.Right) { dir = 0; } else if (e.KeyCode == Keys.Up) { dir = 1; } else if (e.KeyCode == Keys.Left) { dir = 2; } else if (e.KeyCode == Keys.Down) { dir = 3; } } } }

Försöker altså göra någonting snake-liknande, och blacksq är själva "ormen" - en svart fyrkant i en picturebox. Vill ni ha designer-koden också så säg till, program.cs innehåller ingenting extra.

Finns det någon som kan lära mig hur man undviker problemet? Känns som att en lösning vore att köra alla entrådat, men det känns bättre att veta med tanke på eventuella senare kreationer som drar lite mera kraft.

Visa signatur

Pappy :"Backup: Skyddar mot datafel när du på fyllan raderar 200GB pr0n och laddar hem två säsonger teletubbies istället."
Jocke1100 :"Det är väl en mekanisk kylavledning... Typ analog kylpasta..."

Permalänk
Medlem

Jag vet inte riktigt vad du försöker göra, jag ser inget om fler trådar i din kod, men det låter som om du bör använda delegater. C# vill i alla fall att man ska göra det om man försöker modifiera data i en tråd från en annan tråd. Se t.ex. http://jamesrossiter.wordpress.com/2008/08/22/updating-gui-from-other-threads-in-c/. Det finns många exempel om man söker på delegates och/eller thread i Google (just att uppdatera GUI från en s.k. worker thread är ett vanligt exempel).

Permalänk
Skrivet av Thomas H:

Jag vet inte riktigt vad du försöker göra, jag ser inget om fler trådar i din kod, men det låter som om du bör använda delegater. C# vill i alla fall att man ska göra det om man försöker modifiera data i en tråd från en annan tråd. Se t.ex. http://jamesrossiter.wordpress.com/2008/08/22/updating-gui-from-other-threads-in-c/. Det finns många exempel om man söker på delegates och/eller thread i Google (just att uppdatera GUI från en s.k. worker thread är ett vanligt exempel).

det är precis det jag gör. Tack!

Visa signatur

Pappy :"Backup: Skyddar mot datafel när du på fyllan raderar 200GB pr0n och laddar hem två säsonger teletubbies istället."
Jocke1100 :"Det är väl en mekanisk kylavledning... Typ analog kylpasta..."

Permalänk

Jag ser ett par problem med koden du har där.

1- Du sparar ingen referens till timern efter att du har skapat den. Hur ska du då kunna stänga av den senare? Den kommer förvisso stängas när programmet stängs, men det är som upplagt för diverse race conditions etc.

2- blacksq är alltså en WinForms komponent du har gjort i designern. Reglerna för GUI-komponenter är enkla: du får bara anropa dess metoder eller ändra dess properites ifrån GUI-tråden. Anledningen är att annars så skulle komponenterna vara tvungna att vara multitrådade och det skulle öka risken för fel i komponenterna och sen i programmen avsevärt, när det inte finns nån större vinst med det.

Du anger inget SynchronizationObject till timern, och den kommer då att köras på en ThreadPool-tråd. En ThreadPool-tråd är en "worker-tråd" som systemet kör åt dig, som alltså inte är GUI-tråden.

Genom att ange din Form1 som SynchronizationObject till timern så kommer timerns event att köra på GUI-tråden.

Lägg alltså till: aTimer.SynchronizationObject = this; efter att du skapat timern så borde det fungera bättre.

Nyckeln till framgång när man programmerar multitrådat är att hela tiden ha koll på i vilken tråd som en viss kod körs.