pan
7 天以前 42cb7e13165395327f2f9de6c1def858a18424b2
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_BasicService/InvokeMESService.cs
@@ -245,9 +245,7 @@
        public async Task<WebResponseContent> BatchOrderFeedbackToMes(List<string> orderNos, int inout)
        {
            try
            {             // 1. ã€å†…存锁抢占】
                //if (MemoryLockManager.TryAcquireLock(orderNos[0]))
                //{
            {
                   
                        if (inout == 1)
                        {
@@ -913,52 +911,188 @@
    public static class MemoryLockManager
    {
        // å­˜å‚¨èµ„源ID及其对应的锁对象。使用 ConcurrentDictionary ç¡®ä¿å¯¹å­—典操作本身的线程安全。
        private static readonly ConcurrentDictionary<string, object> _resourceLocks = new ConcurrentDictionary<string, object>();
        // å­˜å‚¨èµ„源锁的元数据(锁对象、持有线程、占用时间、超时时间)
        private class LockMetadata
        {
            public object LockObject { get; } = new object();
            public int HoldingThreadId { get; set; } = -1; // æŒæœ‰é”çš„线程ID
            public DateTime AcquireTime { get; set; } // èŽ·å–é”çš„æ—¶é—´
            public TimeSpan Timeout { get; set; } // é”è¶…æ—¶æ—¶é—´
            public bool IsReleased { get; set; } // æ˜¯å¦å·²é‡Šæ”¾
        }
        // å…¨å±€é™æ€é”ï¼šç”¨äºŽä¿æŠ¤ _resourceLocks å­—典中 GetOrAdd æˆ– TryRemove æ—¶çš„竞争
        private static readonly object _globalLocker = new object();
        // èµ„源ID -> é”å…ƒæ•°æ®
        private static readonly ConcurrentDictionary<string, LockMetadata> _resourceLocks = new();
        // å…¨å±€é”ï¼ˆä¿æŠ¤é”å…ƒæ•°æ®çš„创建/删除)
        private static readonly object _globalLocker = new();
        // éšæœºæ•°ç”Ÿæˆå™¨ï¼ˆç”¨äºŽç”Ÿæˆ3-5秒随机超时)
        private static readonly Random _random = new Random();
        /// <summary>
        /// å°è¯•锁定一个资源ID。
        /// å°è¯•锁定资源(带超时自动释放)
        /// </summary>
        /// <param name="resourceId">要锁定的资源ID(例如 InboundRecord ID)</param>
        /// <param name="resourceId">资源ID</param>
        /// <param name="timeoutSeconds">超时时间(默认3-5秒随机)</param>
        /// <returns>是否成功获取锁</returns>
        public static bool TryAcquireLock(string resourceId)
        public static bool TryAcquireLock(string resourceId, int? timeoutSeconds = null)
        {
            object lockObject = null;
            if (string.IsNullOrEmpty(resourceId))
                throw new ArgumentNullException(nameof(resourceId));
            // æ ¸å¿ƒæ€è·¯ï¼šä¸ºæ¯ä¸ªèµ„源创建一个唯一的锁对象
            // ç¡®å®šè¶…时时间(3-5秒随机)
            var timeout = TimeSpan.FromSeconds(timeoutSeconds ?? _random.Next(3, 6));
            var currentThreadId = Thread.CurrentThread.ManagedThreadId;
            LockMetadata lockMeta = null;
            lock (_globalLocker)
            {
                // å¦‚果资源ID不在字典中,则添加一个新的锁对象
                // å¦åˆ™ï¼Œä½¿ç”¨å·²å­˜åœ¨çš„锁对象
                lockObject = _resourceLocks.GetOrAdd(resourceId, new object());
                // èŽ·å–æˆ–åˆ›å»ºé”å…ƒæ•°æ®
                lockMeta = _resourceLocks.GetOrAdd(resourceId, key => new LockMetadata());
                // é˜²æ­¢é‡å¤èŽ·å–ï¼ˆå½“å‰çº¿ç¨‹å·²æŒæœ‰é”ï¼‰
                if (lockMeta.HoldingThreadId == currentThreadId && !lockMeta.IsReleased)
                    return true; // çº¿ç¨‹å¯é‡å…¥
            }
            // å°è¯•获取资源特定的锁
            // ä½¿ç”¨ Monitor.TryEnter é¿å…é˜»å¡žï¼Œå¹¶å®žçŽ°éžé˜»å¡žçš„æŠ¢é”
            return Monitor.TryEnter(lockObject);
            // å°è¯•获取锁(非阻塞)
            if (!Monitor.TryEnter(lockMeta.LockObject))
                return false;
            // æ ‡è®°é”æŒæœ‰çŠ¶æ€
            lockMeta.HoldingThreadId = currentThreadId;
            lockMeta.AcquireTime = DateTime.Now;
            lockMeta.Timeout = timeout;
            lockMeta.IsReleased = false;
            // å¯åŠ¨è¶…æ—¶è‡ªåŠ¨é‡Šæ”¾ä»»åŠ¡
            _ = Task.Delay(timeout).ContinueWith(_ =>
            {
                try
                {
                    ReleaseLock(resourceId, force: true);
                }
                catch (Exception ex)
                {
                    // è®°å½•超时释放异常
                    Console.WriteLine($"资源[{resourceId}]超时自动释放失败:{ex.Message}");
                }
            });
            return true;
        }
        /// <summary>
        /// é‡Šæ”¾èµ„源ID的锁定。
        /// é‡Šæ”¾èµ„源锁
        /// </summary>
        /// <param name="resourceId">要释放的资源ID</param>
        public static void ReleaseLock(string resourceId)
        /// <param name="resourceId">资源ID</param>
        /// <param name="force">是否强制释放(超时自动释放时使用)</param>
        public static void ReleaseLock(string resourceId, bool force = false)
        {
            if (_resourceLocks.TryGetValue(resourceId, out object lockObject))
            {
                // ç¡®ä¿é‡Šæ”¾çš„æ˜¯å½“前线程持有的锁
                if (Monitor.IsEntered(lockObject))
                {
                    Monitor.Exit(lockObject);
            if (string.IsNullOrEmpty(resourceId))
                throw new ArgumentNullException(nameof(resourceId));
                    // é‡Šæ”¾é”åŽï¼Œå°è¯•从字典中移除这个锁对象,清理内存。
                    // å¿…须在 Monitor.Exit ä¹‹åŽæ‰§è¡Œã€‚
            if (!_resourceLocks.TryGetValue(resourceId, out var lockMeta))
                return;
            var currentThreadId = Thread.CurrentThread.ManagedThreadId;
            // æ ¡éªŒé‡Šæ”¾åˆæ³•性:仅持有锁的线程或强制释放可执行
            if (!force && lockMeta.HoldingThreadId != currentThreadId)
            {
                // éžæŒæœ‰çº¿ç¨‹å°è¯•释放,抛出异常或返回(根据业务选择)
                throw new InvalidOperationException($"线程[{currentThreadId}]无权释放资源[{resourceId}]的锁(当前持有线程:{lockMeta.HoldingThreadId})");
            }
            // åŒé‡æ ¡éªŒé”çŠ¶æ€
                    lock (_globalLocker)
                    {
                        _resourceLocks.TryRemove(resourceId, out _);
                if (lockMeta.IsReleased)
                    return;
                // ç¡®ä¿é”è¢«å½“前线程持有(强制释放除外)
                if (Monitor.IsEntered(lockMeta.LockObject))
                {
                    try
                    {
                        Monitor.Exit(lockMeta.LockObject);
                    }
                    catch (SynchronizationLockException)
                    {
                        // å·²è¢«é‡Šæ”¾ï¼Œå¿½ç•¥
                        return;
                    }
                }
                // æ ‡è®°é”å·²é‡Šæ”¾
                lockMeta.IsReleased = true;
                lockMeta.HoldingThreadId = -1;
                // å»¶è¿Ÿæ¸…理锁元数据(避免并发创建)
                // ç­‰å¾…1秒后清理,防止刚释放就有新线程抢锁导致重复创建
                _ = Task.Delay(1000).ContinueWith(_ =>
                {
                    lock (_globalLocker)
                    {
                        // ä»…当锁未被重新持有且已释放时清理
                        if (_resourceLocks.TryGetValue(resourceId, out var meta)
                            && meta.IsReleased
                            && meta.HoldingThreadId == -1)
                        {
                            _resourceLocks.TryRemove(resourceId, out var _resid);
                        }
                    }
                });
            }
        }
        /// <summary>
        /// æ£€æŸ¥èµ„源是否被锁定
        /// </summary>
        public static bool IsLocked(string resourceId)
        {
            if (!_resourceLocks.TryGetValue(resourceId, out var meta))
                return false;
            return !meta.IsReleased && meta.HoldingThreadId != -1;
        }
        public static void TestUsed()
        {
            string orderNo = "testt";
            bool lockAcquired = false;
            try
            {
                // å°è¯•获取锁(自动3-5秒超时)
                lockAcquired = MemoryLockManager.TryAcquireLock(orderNo);
                if (lockAcquired)
                {
                    // æ‰§è¡Œä¸šåŠ¡é€»è¾‘ï¼ˆå¦‚å¤„ç†è®¢å•ï¼‰
                    Console.WriteLine($"线程[{Thread.CurrentThread.ManagedThreadId}]获取锁:{orderNo}");
                    // æ¨¡æ‹Ÿä¸šåŠ¡è€—æ—¶ï¼ˆæµ‹è¯•è¶…æ—¶é‡Šæ”¾ï¼‰
                    // Thread.Sleep(6000);
                }
                else
                {
                    Console.WriteLine($"资源[{orderNo}]被占用,获取锁失败");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"业务处理异常:{ex.Message}");
            }
            finally
            {
                // é‡Šæ”¾é”ï¼ˆä»…当成功获取时)
                if (lockAcquired)
                {
                    try
                    {
                        MemoryLockManager.ReleaseLock(orderNo);
                        Console.WriteLine($"线程[{Thread.CurrentThread.ManagedThreadId}]释放锁:{orderNo}");
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine($"释放锁失败:{ex.Message}");
                    }
                }
            }