即使我确定它存在,ConcurrentDictionary也找不到密钥

时间:2013-07-01 22:21:00

标签: c# string multithreading stream concurrentdictionary

在我的静态课程中,我有这个:

static var cache = new ConcurrentDictionary<string, object>();

在第1号线中,我这样做:

cache.TryAdd (stringFromSomewhere, newlyCreatedObject); 
Console.WriteLine(stringFromSomewhere); // Outputs "abc"

线程#1之后的几秒钟,在线程#2中:

if(cache.ContainsKey(stringFromSomewhereElse))
    Console.WriteLine("Yes, it exists.");
else
    Console.WriteLine("This did not exist: " + stringFromSomewhereElse);

输出“这不存在:abc”

然后在线程#2之后的几秒钟内执行线程#3:

foreach(var kvp in cache)
{
    Console.WriteLine("string: " + kvp.Key);
    if(cache.ContainsKey(kvp.Key))
        Console.WriteLine("Yes, it exists.");
    else
        Console.WriteLine("This did not exist: " + kvp.Key);
}

我得到输出“string:abc”和“是的,它存在。”

在线程#1中,我使用MD5创建字符串,如下所示:

Convert.ToBase64String (md5.ComputeHash(Encoding.ASCII.GetBytes(value)))

在线程#2中,我从字节流中获取字符串,其中字符串使用UTF8编码写入,然后再次使用UTF8编码从字节读取字符串。

在线程#3中,我通过循环ConcurrentDictionary获得字符串。

我在这里缺少什么?据我所知,Thread#2应该像Thread#3一样。

我有两种可能性,我认为这两种可能性都很远:

  • 这是我不知道的某种同步问题吗?
  • 或者字符串是否有所不同?当我将它输出到控制台时,它没有区别。

任何人都有其他想法或解决方案吗?

修改

我将数据写入流中,如下所示:

string data = System.Web.HttpUtility.UrlEncode(theString);
byte[] buffer = Encoding.UTF8.GetBytes (data);
NetworkStream stream = client.GetStream(); // TcpClient client;
stream.Write (buffer, 0, buffer.Length);

然后我从流中读取数据:

string data = "";
NetworkStream stream = client.GetStream(); // TcpClient client;
byte[] bytes = new byte[4096];
do {   
    int i = stream.Read (bytes, 0, bytes.Length);
    data += Encoding.UTF8.GetString (bytes, 0, i);
} while(stream.DataAvailable);
string theString = HttpUtility.UrlDecode(data);

2 个答案:

答案 0 :(得分:1)

如果您正在将字节写入网络流然后将其读回,则必须在数据前面加上一个值,该值表示后面有多少字节,或者您需要一个数据结束标记。编写代码的方式,接收代码很可能只是获取部分数据。

想象一下,例如,您的密钥是“HelloWorld”。您的发送代码将字符串发送出去。接收代码看到缓冲区中的“Hello”部分,抓取它,检查是否有更多数据可用,这不是因为网络传输线程还没有完成将其复制到缓冲区。

所以你只得到一部分字符串。

可能发生的另一件事是你读得太多了。如果您将两个字符串写入网络流并且您的读取器读取它们就好像它们是单个字符串一样,就会发生这种情况。

要做得对,你应该这样做:

int dataLength = buffer.Length;
byte[] lengthBuff = BitConverter.GetBytes(dataLength);
stream.Write(lengthBuff, 0, lengthBuff.Length);  // write length
stream.Write(buffer, 0, buffer.Length);  // write data

然后通过首先读取长度然后从流中读取那么多字节来读取它。

或者,您可以使用数据结束标记:

stream.Write(buffer, 0, buffer.Length);  // write data
buffer[0] = end_of_data_byte;
stream.Write(buffer, 0, 1);  // write end of data

读者会读取字节,直到它结束数据标记。

您用于结束数据标记的内容取决于您。它应该是不在正常数据流中的东西。

就个人而言,我会选择长度前缀。

答案 1 :(得分:0)

很难理解你的问题的流程 - 但有一点我注意到:你在网络写()后刷新()吗?否则,您可能会在写入时出现延迟,这通常会导致与时序相关的问题。