多线程同步:基于栈式同步

    什么是基于栈式同步?这是一种完全基于异步环境的线程处理之间的同步,可能这让人有些难以理解,但我们想想一下当你开辟了多条线程用于处理某种事物的时候,例如你访问 Redis 中的 Set 接口,大多数的客户端都需要阻塞当前线程,由另一个线程发射信号通知内核停止阻塞(恢复线程的上下文),但当这个同时阻塞的线程数量过多的时候,对内核与处理器的负载是很重的,而“基于栈式同步”是可以解决这些问题的。

    但“基于栈式同步”本身存在很多的局限性,虽然它最好的实现是基于“自选锁”,其本身处理对锁的占有时间足够短(是一个链式结构)但不可否认的是,它具有 “爆栈(栈溢出)” 的问题,但可以通过一些手段进行有效的控制。

    本文中提出的代码来自本人 github 上的开源项目 “malock CA*”,它参照了 “AutoResetEvent(自动重置内核事件对象)”的接口设计,是一种不可 “重入” 的锁。

    参考源:https://github.com/liulilittle/malock

    还有另一个致命的问题,就是说这种类型锁,它并不是很适合 “C/C++” 这类型的语言,这是由于 “语言” 本身的特性造成的,但它却很适合 “C# / VB.NET / Java” 这些语言,这不仅仅是 lambda 底层实现机制的问题。

    这是一个“基于栈式”的锁,典型应用案例,从上述代码可以很直接的反应上面提到的一些问题,但这类的锁虽然是“完全异步” 的,的确可以获取到更好的效率与能耗,但也是因为这个特性,会促使它必须依赖于实现 “语言” 的本身特性才可以,否则编码复杂度的成本就不能被忽略,另一点它依赖了某些处理线程的堆栈,这就好比说虽然它异步处理,但最终执行还是需要依赖某个具体的执行线程的。

    或许你可能会想到它单独运行了一个线程,但这是错误错的(单独建立线程会增大资源的消耗降低锁的效能,而且意义不是很大),它是利用诱发 “Set” 信号的线程进行处理的,例如:它可能是第一次调用 WaitOne 时,锁的原子信号处于 Set 态,那么处理线程就是第一次调用 WaitOne 的线程,但在一瞬间增加了大量需要 “异步同步” 的 WaitOne,处理线程可能会处于活动的状态,就是说有四条调用 Set 的线程,那么这四条线程可能都会执行不属于本身的 “WaitOne” 临界区内的任务

    你可以从此获取到   “ https://github.com/liulilittle/malock/blob/master/malock/Core/StackAutoResetEvent.cs ” 的实现源,但是既然知道有 “爆栈” 方面的问题,难道就无法根治了?所以在 malock 的实现中提供了另外一种的 “基于栈式同步” 的锁的实现,用于解决这个问题。

namespace malock_client
{
    using malock.Core;
    using System;
    using System.Threading;

    class Program
    {
        static int num = 0;

        static void Main(string[] args) 
        {
            StackAutoResetEvent events = new StackAutoResetEvent(false);
            for (int i = 0; i < 20; i++)
            {
                new Thread(() => events.WaitOne(() =>
                {
                    Console.WriteLine(++num);
                    events.Set();
                })).Start();
            }
            events.Set();
            Console.ReadLine();
        }
    }
}

    AsyncAutoResetEvent 类用以解决这个问题,它与 “StackAutoResetEvent” 的实现原理几乎大同小易,不过它利用一种状态标识用于控制处理的线程归属与 “暴栈”,但它有一个不太好的地方就是说,它可能会让同一条执行线程处理所有的临界区任务,这是一种比较坏的情况,当然持有锁的时间过程都不被释放本身应用锁的 “代码” 就存在很多的问题,这不是选用任何种锁解决解决的,而是需要从源头与根本上解决问题,才是正确的。

namespace malock_client
{
    using malock.Core;
    using System;
    using System.Threading;

    class Program
    {
        static int num = 0;

        static void Main(string[] args) 
        {
            AsyncAutoResetEvent events = new AsyncAutoResetEvent(false);
            for (int i = 0; i < 20; i++)
            {
                new Thread(() => events.WaitOne((state) =>
                {
                    Console.WriteLine(++num);
                    events.Set(state);
                })).Start();
            }
            events.Set(true);
            Console.ReadLine();
        }
    }
}

猜你喜欢

转载自blog.csdn.net/liulilittle/article/details/81979321
今日推荐