3

我只是继承了这个由多个线程访问的代码。我刚刚介绍了两把锁——但我想知道是否还有什么我应该知道的。我没有在多线程应用程序中工作的重要经验。

namespace Helpers.Security
{
    public static class Encryption
    {
        #region "Random Numbers"
        static readonly int[] _randData = {
            //A gigantic list of numbers...
        };
        #endregion

        private static int _randIdx = 0;

        private static readonly object _encryptLock = new object();
        private static readonly object _decryptLock = new object();

        //HG 2009-JUN-11 - Added Reverse Methods from PF's Merge updates in [CDataServerBootStrapper]
        public static string EncryptStringReverse(string c_string)
        {
            return Encrypt(ReverseString(c_string));
        }
        public static string DecryptStringReverse(string c_string)
        {
            return Decrypt(ReverseString(c_string));
        }
        private static string ReverseString(string inputString)
        {
            string result = string.Empty;
            for (int pos = inputString.Length - 1; pos >= 0; pos--)
                result += inputString[pos];

            return result;
        }

        public static string Encrypt(string c_string)
        {
            if (c_string == null || c_string.Equals(string.Empty)) return string.Empty;
            int[] sasc = new int[224];
            char[] chash = new char[224];
            bool isExisting = false;
            string encstr = "";
            int sl = c_string.Length;

            lock (_encryptLock)
            {
                _randIdx = 0;

                for (int v = 0; v < 223; v++)
                {
                    sasc[v] = '\0';
                }
                for (int cl = 0; cl < sl; cl++)
                {
                    for (int a = 0; a < 223; a++)
                    {
                        int rnum = _randData[_randIdx++];
                        for (int y = 0; y < 223; y++)
                        {
                            if (sasc[y] == rnum)
                            {
                                isExisting = true;
                            }
                        }
                        if (isExisting == false)
                        {
                            sasc[a] = rnum;
                            chash[a] = (char) rnum;
                        }
                        else
                            a--;
                        isExisting = false;
                    }
                    chash[223] = '\0';
                    string strhash = new string(chash);
                    for (int v = 0; v < 223; v++)
                    {
                        sasc[v] = '\0';
                    }
                    encstr = encstr + strhash[c_string[cl] - 30];
                }
            }

            // Convert the wide-character string to multibyte string
            string sWholeHex = "";
            foreach (char c in encstr)
            {
                byte val = (byte) c;

                sWholeHex += val.ToString("X2");
            }

            return (sWholeHex.Trim().Replace("\0", ""));
        }

        public static string Decrypt(string c_string)
        {
            if (c_string == null || c_string.Equals(string.Empty)) return string.Empty;

            string szTemp = c_string;
            int nCtr = 0;
            byte[] byToDecrypt = new byte[1024];
            char[] chash = new char[223];
            char[] cencstr = new char[5000];
            int[] sasc = new int[223];
            bool isExisting = false;

            lock (_decryptLock)
            {
                for (int b = 0; b < 1024; b++)
                    byToDecrypt[b] = 0;

                int r;
                string sToDecrypt = string.Empty;
                for (r = 0; r < szTemp.Length - 1; r += 2)
                {
                    byte b2 = 0;
                    char c = szTemp[r];
                    if (c >= '0' && c <= '9')
                        b2 += (byte) (c - '0');
                    else if (c >= 'A' && c <= 'Z')
                        b2 += (byte) (c - 'A' + 10);

                    b2 *= 16;
                    c = szTemp[r + 1];
                    if (c >= '0' && c <= '9')
                        b2 += (byte) (c - '0');
                    else if (c >= 'A' && c <= 'Z')
                        b2 += (byte) (c - 'A' + 10);

                    byToDecrypt[nCtr++] = b2;
                    sToDecrypt += (char) b2;
                }

                _randIdx = 0;

                int sl = sToDecrypt.Length;

                for (int v = 0; v < 223; v++)
                {
                    sasc[v] = '\0';
                }
                int cl;
                for (cl = 0; cl < sl; cl++)
                {
                    for (int a = 0; a < 223; a++)
                    {
                        int rnum = _randData[_randIdx++];
                        for (int y = 0; y < 223; y++)
                        {
                            if (sasc[y] == rnum)
                            {
                                isExisting = true;
                            }
                        }
                        if (isExisting == false)
                        {
                            sasc[a] = rnum;
                            chash[a] = (char) rnum;
                        }
                        else
                        {
                            a--;
                        }
                        isExisting = false;
                    }
                    string strhash = new string(chash);
                    int v;
                    for (v = 0; v < 223; v++)
                    {
                        if (sToDecrypt[cl] == strhash[v])
                            cencstr[cl] = (char) ((byte) (v + 30));
                    }

                    for (v = 0; v < 223; v++)
                    {
                        sasc[v] = 0;
                    }
                }
                cencstr[cl] = '\0';
            }

            string encstr = new string(cencstr);

            return (encstr.Trim().Replace("\0", ""));
        }
    }
}

我唯一的想法是这里有很多工作要做,所以我应该把所有的工作都锁起来,以确保我不只是把锁定问题推到别处。话虽如此——只有两个变量是全局可访问的……_randIdx 和 _randData。我不确定这是否是决定锁定什么的因素。

4

4 回答 4

2

这取决于你需要什么样的线程安全。

_randIdx可以由两个不同的线程设置和获取,因为您的加密和解密方法使用不同的对象来锁定。您只_randData在每个锁中对数组执行读取,所以这不是问题。

似乎lock只需使用一个本地临时索引就可以轻松实现这一点。这是否有效取决于您。

于 2012-05-16T16:00:16.063 回答
1

您将需要使用相同的锁来保护_randIdx加密和解密中的全局变量。 _randData没有被修改,所以不需要专门保护它。由于该类的所有方法都是static,您没有任何其他成员可以防止模拟访问/修改

于 2012-05-16T16:00:08.217 回答
1

Attila 是正确的,但我将用更多的词来描述这些想法:

您有两个锁定目标(_encryptLock 和 _decryptLock)。您可以在不同的线程上同时输入这些锁。这意味着 Encrypt 方法可以在 Decrypt 方法使用它时将 _randidx 设置为 0(不好)。 每组受保护实例仅使用一个锁定目标。

您实际上不需要锁来保护 _randData,因为您没有修改它。多个线程可以安全地从同一个数组中读取。_randData 中的实例也不需要保护,因为它们是值类型 - 访问该数组的任何人都会获得一份副本并且不会修改原始数据。

如果将 _randidx 更改为两个方法范围的变量,则不需要锁来保护它。只属于一个线程的,是安全的。

由于您没有需要锁保护的实例,因此您可能没有锁。

于 2012-05-16T16:07:18.453 回答
0

您应该尽量减少在一个lock块中执行的“工作”量。我建议将锁内的工作重构到另一个可能通过 (via [Array.Copy(...)][1])的对象_randData

你真的在修改 _randData吗?如果没有,我认为没有理由锁定。您还使用了 2 个不同的锁 - 一个用于加密,一个用于解密。是否有意让您能够_randData从 2 个线程访问?拥有 2 个锁定对象将允许这种情况发生。

于 2012-05-16T16:05:30.183 回答