mirror of
https://github.com/osukey/osukey.git
synced 2025-05-21 05:27:17 +09:00
Fix non-safe thread access to room users on room join
This commit is contained in:
parent
e0198c36ae
commit
5ce5b6cec0
@ -4,8 +4,10 @@
|
|||||||
#nullable enable
|
#nullable enable
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
@ -108,7 +110,9 @@ namespace osu.Game.Online.Multiplayer
|
|||||||
|
|
||||||
Debug.Assert(Room != null);
|
Debug.Assert(Room != null);
|
||||||
|
|
||||||
await Task.WhenAll(Room.Users.Select(PopulateUser));
|
var users = getRoomUsers();
|
||||||
|
|
||||||
|
await Task.WhenAll(users.Select(PopulateUser));
|
||||||
|
|
||||||
updateLocalRoomSettings(Room.Settings);
|
updateLocalRoomSettings(Room.Settings);
|
||||||
}
|
}
|
||||||
@ -121,14 +125,17 @@ namespace osu.Game.Online.Multiplayer
|
|||||||
protected abstract Task<MultiplayerRoom> JoinRoom(long roomId);
|
protected abstract Task<MultiplayerRoom> JoinRoom(long roomId);
|
||||||
|
|
||||||
public virtual Task LeaveRoom()
|
public virtual Task LeaveRoom()
|
||||||
|
{
|
||||||
|
Schedule(() =>
|
||||||
{
|
{
|
||||||
if (Room == null)
|
if (Room == null)
|
||||||
return Task.CompletedTask;
|
return;
|
||||||
|
|
||||||
apiRoom = null;
|
apiRoom = null;
|
||||||
Room = null;
|
Room = null;
|
||||||
|
|
||||||
Schedule(() => RoomChanged?.Invoke());
|
RoomChanged?.Invoke();
|
||||||
|
});
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
@ -360,6 +367,31 @@ namespace osu.Game.Online.Multiplayer
|
|||||||
/// <param name="multiplayerUser">The <see cref="MultiplayerRoomUser"/> to populate.</param>
|
/// <param name="multiplayerUser">The <see cref="MultiplayerRoomUser"/> to populate.</param>
|
||||||
protected async Task PopulateUser(MultiplayerRoomUser multiplayerUser) => multiplayerUser.User ??= await userLookupCache.GetUserAsync(multiplayerUser.UserID);
|
protected async Task PopulateUser(MultiplayerRoomUser multiplayerUser) => multiplayerUser.User ??= await userLookupCache.GetUserAsync(multiplayerUser.UserID);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieve a copy of users currently in the joined <see cref="Room"/> in a thread-safe manner.
|
||||||
|
/// This should be used whenever accessing users from outside of an Update thread context (ie. when not calling <see cref="Drawable.Schedule"/>).
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A copy of users in the current room, or null if unavailable.</returns>
|
||||||
|
private List<MultiplayerRoomUser>? getRoomUsers()
|
||||||
|
{
|
||||||
|
List<MultiplayerRoomUser>? users = null;
|
||||||
|
|
||||||
|
ManualResetEventSlim resetEvent = new ManualResetEventSlim();
|
||||||
|
|
||||||
|
// at some point we probably want to replace all these schedule calls with Room.LockForUpdate.
|
||||||
|
// for now, as this would require quite some consideration due to the number of accesses to the room instance,
|
||||||
|
// let's just to a schedule for the non-scheduled usages instead.
|
||||||
|
Schedule(() =>
|
||||||
|
{
|
||||||
|
users = Room?.Users.ToList();
|
||||||
|
resetEvent.Set();
|
||||||
|
});
|
||||||
|
|
||||||
|
resetEvent.Wait(100);
|
||||||
|
|
||||||
|
return users;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Updates the local room settings with the given <see cref="MultiplayerRoomSettings"/>.
|
/// Updates the local room settings with the given <see cref="MultiplayerRoomSettings"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user