下面的代码是可重入且线程安全的吗?

发布于 2024-12-08 11:46:54 字数 720 浏览 0 评论 0原文

下面的代码是可重入的吗?

如果 this.NextToExecuteIndex 声明为 private int NextToExecuteIndex = 0; 并且不在其他地方计算,它是线程安全的吗?

    protected override void Poll(object sender, System.Timers.ElapsedEventArgs e)
    {
        int index;

        object locker = new object();

        lock (locker)
        {
            Interlocked.Increment(ref this.NextToExecuteIndex);

            if (this.NextToExecuteIndex >= this.ReportingAgentsTypes.Count())
            {
                this.NextToExecuteIndex = 0;
            }

            index = this.NextToExecuteIndex;
        }

        var t = this.ReportingAgentsTypes[index];

        Console.WriteLine(t.ToString());
    }

Is the following code is reentrant?

Is it thread-safe, if this.NextToExecuteIndex is declared private int NextToExecuteIndex = 0; and not computed anywhere else?

    protected override void Poll(object sender, System.Timers.ElapsedEventArgs e)
    {
        int index;

        object locker = new object();

        lock (locker)
        {
            Interlocked.Increment(ref this.NextToExecuteIndex);

            if (this.NextToExecuteIndex >= this.ReportingAgentsTypes.Count())
            {
                this.NextToExecuteIndex = 0;
            }

            index = this.NextToExecuteIndex;
        }

        var t = this.ReportingAgentsTypes[index];

        Console.WriteLine(t.ToString());
    }

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

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

发布评论

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

评论(2

坏尐絯℡ 2024-12-15 11:46:54

不,这根本不是线程安全的。由于该对象是线程本地的,所以锁没有任何作用。它需要被所有调用线程共享。一旦解决了这个问题,您就不需要使用互锁增量,因为锁会串行执行。

作为一般规则,您应该将 locker 放置在与您要保护的资源相同的级别。如果资源由实例拥有,那么应该是locker。同样,如果资源归类所有。

至于可重入性,lock 关键字使用可重入锁,即如果该线程持有该锁,则允许该线程进入。这可能不是你想要的。但如果你有一个不可重入锁,那么你只会因可重入调用而陷入死锁。我认为你也不会想要这样。

你看起来想要一个环绕增量。只要集合不被修改,就可以通过互锁操作(即无锁)来实现。如果是这样,那么可以这样写:

do
{
    int original = this.NextToExecuteIndex;
    int next = original+1;
    if (next == this.ReportingAgentsTypes.Count())
        next = 0;
}
while (Interlocked.CompareExchange(ref this.NextToExecuteIndex, next, original) != original);

注意:您应该将NextToExecuteIndex声明为易失性的。

No this is not thread-safe at all. The lock has no effect since the object is local to the thread. It needs to be shared by all calling threads. Once you fix that you don't need to use interlocked increment because the lock serialises execution.

As a general rule you should place locker at the same level as the resource you are protecting. If the resource is owned by the instance then so should be locker. Similarly if the resource is owned by the class.

As for re-entrancy, the lock keyword uses a re-entrant lock, i.e. one that lets the same thread in if the lock is held by that thread. That's probably not what you want. But if you had a non re-entrant lock then you would just deadlock yourself with a re-entrant call. And I don't think you'd want that either.

You look like you want a wrap around increment. So long as the collection is not being modified, this can be achieved with interlocked operations, i.e. lock free. If so then it can be written like this:

do
{
    int original = this.NextToExecuteIndex;
    int next = original+1;
    if (next == this.ReportingAgentsTypes.Count())
        next = 0;
}
while (Interlocked.CompareExchange(ref this.NextToExecuteIndex, next, original) != original);

Note: You should declare NextToExecuteIndex as volatile.

懒的傷心 2024-12-15 11:46:54

绝对不是。这是你的问题object locker = new object();。您将创建一个新对象并每次锁定它。

Absolutely not. This is your problem object locker = new object();. You will create a new object and lock on it every time.

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