“对象同步方法是从非同步的代码块中调用的”回调测试错误

发布于 2025-02-11 02:11:42 字数 1527 浏览 0 评论 0原文

如果收到了预期数量的异步回调,则应该测试以下类:

class Program
{
    static List<int> callbackObjects = new List<int>();
    static int expectedNumberOfCallbacks;
    static void Main(string[] args)
    {
        expectedNumberOfCallbacks = 10;
        Monitor.Enter(callbackObjects);
        CallbackTest.CallbackTester.TriggerCallbacks(expectedNumberOfCallbacks,Callback);
        Monitor.Wait(callbackObjects,10000);
        Assert.AreEqual(callbackObjects.Count, expectedNumberOfCallbacks);
    }

    private static void Callback(int callbackObject)
    {
        callbackObjects.Add(callbackObject);
        Console.WriteLine($"Callback number {callbackObjects.Count}");
        if(callbackObjects.Count == expectedNumberOfCallbacks)
        {
            Monitor.Exit(callbackObjects);
        }
    }
}

代码输出,

Callback number 1
Callback number 2
Callback number 3
Callback number 4
Callback number 5
Callback number 6
Callback number 7
Callback number 8
Callback number 9
Callback number 10

但随后会抛出一个

System.Threading.SynchronizationLockException: 'Object synchronization method was called from an unsynchronized block 

执行权,

Monitor.Exit(callbackObjects);

是因为Monitor.enter.enter.entermonitor.exit 在不同的范围/线程中调用?

如何重写代码,

Assert.AreEqual(callbackObjects.Count, expectedNumberOfCallbacks)

在收到预期的回调数或预定义超时之后,在main中进行测试?

The following class is supposed to test, if an expected number of asynchronous Callbacks was received:

class Program
{
    static List<int> callbackObjects = new List<int>();
    static int expectedNumberOfCallbacks;
    static void Main(string[] args)
    {
        expectedNumberOfCallbacks = 10;
        Monitor.Enter(callbackObjects);
        CallbackTest.CallbackTester.TriggerCallbacks(expectedNumberOfCallbacks,Callback);
        Monitor.Wait(callbackObjects,10000);
        Assert.AreEqual(callbackObjects.Count, expectedNumberOfCallbacks);
    }

    private static void Callback(int callbackObject)
    {
        callbackObjects.Add(callbackObject);
        Console.WriteLine(
quot;Callback number {callbackObjects.Count}");
        if(callbackObjects.Count == expectedNumberOfCallbacks)
        {
            Monitor.Exit(callbackObjects);
        }
    }
}

The code outputs

Callback number 1
Callback number 2
Callback number 3
Callback number 4
Callback number 5
Callback number 6
Callback number 7
Callback number 8
Callback number 9
Callback number 10

but then it throws an

System.Threading.SynchronizationLockException: 'Object synchronization method was called from an unsynchronized block 

on executing

Monitor.Exit(callbackObjects);

Is it because Monitor.Enter and Monitor.Exit are invoked in different scopes/threads?

How can I rewrite the code, to do the

Assert.AreEqual(callbackObjects.Count, expectedNumberOfCallbacks)

test in Main, either after the expected number of callbacks was received or a predefined timeout?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

徒留西风 2025-02-18 02:11:42

是因为monitor.enterMonitor.exit在不同的范围/线程中调用?

是的,正是那样。 Monitor是线程的。

但是,IMO您还应该考虑是否可以重叠多个回调;如果是,则需要在回调内同步,以便callbackobjects.add定义很好。您的真正需要的是lock pulse :

   static void Main(string[] args)
    {
        expectedNumberOfCallbacks = 10;
        lock (callbackObjects)
        {
            CallbackTest.CallbackTester.TriggerCallbacks(
                expectedNumberOfCallbacks,Callback);
            Monitor.Wait(callbackObjects, 10000);
            Assert.AreEqual(callbackObjects.Count, expectedNumberOfCallbacks);
        }
    }

    private static void Callback(int callbackObject)
    {
        lock (callbackObjects)
        {
            callbackObjects.Add(callbackObject);
            Console.WriteLine($"Callback number {callbackObjects.Count}");
            if(callbackObjects.Count == expectedNumberOfCallbacks)
            {
                Monitor.Pulse(callbackObjects);
            }
        }
    }

等待发布监视器和等待信号或超时重新启动它; pulsepulseall是将该信号发送到等待线程(或线程)的原因。

您还可以使用等待的返回值来确定是否发出信号(vs timeout)。

Is it because Monitor.Enter and Monitor.Exit are invoked in different scopes/threads?

Yes, exactly that. Monitor is thread-bound.

However, IMO you should also consider whether the multiple callbacks can themselves be overlapped; if they are, you need to synchronize inside the callback so that callbackObjects.Add is well-defined. It could be that what you really need here is lock and Pulse:

   static void Main(string[] args)
    {
        expectedNumberOfCallbacks = 10;
        lock (callbackObjects)
        {
            CallbackTest.CallbackTester.TriggerCallbacks(
                expectedNumberOfCallbacks,Callback);
            Monitor.Wait(callbackObjects, 10000);
            Assert.AreEqual(callbackObjects.Count, expectedNumberOfCallbacks);
        }
    }

    private static void Callback(int callbackObject)
    {
        lock (callbackObjects)
        {
            callbackObjects.Add(callbackObject);
            Console.WriteLine(
quot;Callback number {callbackObjects.Count}");
            if(callbackObjects.Count == expectedNumberOfCallbacks)
            {
                Monitor.Pulse(callbackObjects);
            }
        }
    }

Wait releases a monitor and waits for either a signal or a timeout to re-acquire it; Pulse and PulseAll are what sends that signal to a waiting thread (or threads).

You can also use the return value from Wait to determine whether or not you got signaled (vs timeout).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文