C# - Multithreading (XNA Spelprogrammering)

Permalänk
Medlem

C# - Multithreading (XNA Spelprogrammering)

Tjo!

Är rätt ny med multithreading och har nu stött på ett problem.

Följande är en Draw() funktion från en class jag använder

public void Draw(SpriteBatch spriteBatch) { if (Visible) { spriteBatch.Draw(background, size, Color.White); foreach (ChatMessage chatMsg in Messages.ToList()) { if (chatMsg != null) { if ((size.Y + chatMsg.Position.Y > size.Y) && (size.Y + chatMsg.Position.Y < size.Y + size.Height)) { if (string.Compare(chatMsg.WhoSays, "YOU") == 0) { spriteBatch.DrawString(font, chatMsg.Text, new Vector2(size.X + chatMsg.Position.X, size.Y + chatMsg.Position.Y), new Color(153, 217, 234)); } else if (string.Compare(chatMsg.WhoSays, "PLAYER") == 0) { spriteBatch.DrawString(font, chatMsg.Text, new Vector2(size.X + chatMsg.Position.X, size.Y + chatMsg.Position.Y), Color.White); } else if (string.Compare(chatMsg.WhoSays, "SYSTEM") == 0) { spriteBatch.DrawString(font, chatMsg.Text, new Vector2(size.X + chatMsg.Position.X, size.Y + chatMsg.Position.Y), Color.Yellow); } } } } chatBox.Draw(spriteBatch); } }

Då den anropas hela tiden samt att jag modiferar Messages-listan i princip hela tiden så får jag tillsist ett error-message vid foreach() efter ett tag, men jag har kollat upp felmeddelandet och vad jag har förstått så försöker jag köra foreach() när den redan körs dvs två trådar försöker köra samma funktion samtidigt... Så min fråga blir då, finns det något sätt att kolla om ingen tråd går igenom listan redan?

Felmeddelande:

ArgumentException unhandled: Destination array was not long enough. Check destIndex and length, and the array's lower bounds.

EDIT: Har kört spelet ett längre tag nu och har Inte fått felmeddelandet igen, men då jag har fått det en gång så måste det ju finnas risk att det kommer att komma igen? Då jag antar att det har med thread timing att göra?

Visa signatur

C#/MonoGame Fanatiker.
Pixel Artist & Game Developer

Permalänk
Medlem

Du har helt rätt. Det är farligt att skriva till och läsa från listan samtidigt.
Det du vill ha kallas för critical sections. Vet inte hur man gör i C# men sök lite så lär du hitta hur man fixar det.

Permalänk
Medlem

Ett enkelt sätt att fixa är att låsa runt varje gång du använder listan med lock. Nånstans definierar du ett lås-objekt, och sen lägger du en lock(lås-objekt){} runt varje ställe som använder Messages-listan.

Tänk bara på att hålla det enkelt! För varje ställe i koden som behöver lock, och för varje nytt objekt som låses ökar risken för att det kan ske deadlocks, och då blir det genast väldigt krångligt. Andra konstiga saker kan hända när det är flera trådar igång som ändrar/läser från samma saker, så man får verkligen passa sig. Det enklaste alternativet är att bara ha en tråd, eller bara en tråd som gör jobb iaf. Finns chans att det blir minst lika snabbt dessutom. Men nu antar jag att du vill testa på flertrådat så det är väl inte ett alternativ

Visa signatur

AK47s for everyone! - Angry mob
Since NaN /= NaN, I think, we should decipher 'NaN' as 'Not a NaN' - Miguel Mitrofanov
(Varför är människan så benägen att tro på Gud?) Antagligen har det lönat sig och evolutionen har drivit fram sådana hjärnor. - Anon

Permalänk
Hedersmedlem
Skrivet av vb:

Ett enkelt sätt att fixa är att låsa runt varje gång du använder listan med lock. Nånstans definierar du ett lås-objekt, och sen lägger du en lock(lås-objekt){} runt varje ställe som använder Messages-listan.

I System.Collections.Concurrent finns också ett antal klasser som är anpassade för situationer som dessa.

Permalänk

I java gör man en metod eller ett block synchronized. Googlade lite snabbt och motsvarande java för mutual exclusion på metod-nivå för C# är att denotera metoden med:

[MethodImpl(MethodImplOptions.Synchronized)]
public void Draw()

Copy+pastea bort mig totalt:/
Permalänk
Medlem

Du kan läsa listan från flera trådar om du vill men du kan absolut inte modifiera listan från flera trådar samtidigt, då blir det kaos tyvärr :/ Så som sagt tidigare, behöver du ändra i trådarna så måste du använda lås. Antingen längre lås eller väldigt korta lås. Fundera på om du verkligen behöver ha flera trådar som ändrar i dina meddelanden samtidigt eller om det är möjligt att få en tråd som sköter all ändring.

Permalänk
Hedersmedlem
Skrivet av 2infinity:

Du kan läsa listan från flera trådar om du vill men du kan absolut inte modifiera listan från flera trådar samtidigt, då blir det kaos tyvärr :/ Så som sagt tidigare, behöver du ändra i trådarna så måste du använda lås. Antingen längre lås eller väldigt korta lås. Fundera på om du verkligen behöver ha flera trådar som ändrar i dina meddelanden samtidigt eller om det är möjligt att få en tråd som sköter all ändring.

Det kan också bli jobbigt om man försöker läsa i en tråd samtidigt som en annan skriver, så man måste tänka även när man läser...