跨线程调用事件?

Calling events cross-threads?

我正在开发一个 class,看起来像这样:

public class MatchmakingService  {
    private bool working;
    private List<MatchmakingUser> matchmakingUsers;
    // ...

    public MatchmakingService()
    {
        matchmakingUsers = new List<MatchmakingUser>();
    }

    public void StartService () {
        var thread = new Thread(this.MatchmakingWork);
        working = true;
        thread.Start();
    }

    void MatchmakingWork () {
        while (working)
        {
            // some work, match found!
            {
                  if(onMatchFound != null)
                      onMatchFound(this, new NewMatchEventArgs(matchmakingUsers[i], matchmakingUsers[j]);
            }
            Thread.Sleep(1000);
        }
    }
}

通常,当找到匹配项时,我会在 MatchFound 上启动一个事件并结束它,但由于服务的线程不同,并且此事件的订阅者将在不同的线程上 --如何处理?我读过这样做不安全,如果这是真的,那么我有什么选择?

注意:我没有使用 WinForms,所以没有控件的调用恶作剧。

最简单的方法是创建队列。有多种方法可以实现队列。我会在 MatchmakingService

中创建一个队列

使用队列存储匹配项,其他线程必须调用RaiseEvents()方法来处理队列。这意味着,另一个线程应该有一个 Timer/DispatcherTimer/While 和睡眠等等...

示例:

public class MatchmakingService
{
    private bool working;
    private List<MatchmakingUser> matchmakingUsers;
    // ...

    // the queue
    private List<NewMatchEventArgs> _queue = new List<NewMatchEventArgs>();


    public MatchmakingService()
    {
        matchmakingUsers = new List<MatchmakingUser>();
    }

    public void StartService()
    {
        var thread = new Thread(this.MatchmakingWork);
        working = true;
        thread.Start();
    }

    void MatchmakingWork()
    {
        while (working)
        {
            // some work, match found!
            {
                lock (_queue)
                    _queue.Add(new NewMatchEventArgs(matchmakingUsers[1], matchmakingUsers[2]));
            }
            Thread.Sleep(1000);
        }
    }

    public void RaiseEvents()
    {
        NewMatchEventArgs[] copyOfQueue;

        // create a copy (bulk action)
        lock (_queue)
        {
            copyOfQueue = _queue.ToArray();
            _queue.Clear();
        }

        // handle the items
        if (onMatchFound != null)
            foreach (var item in copyOfQueue)
                onMatchFound(this, item); // indices are examples

    }

    public event EventHandler<NewMatchEventArgs> onMatchFound;

}