多线程应用程序中的队列<string>的InvalidCastException </string>

时间:2014-02-05 00:24:58

标签: c# string exception .net

声明为类变量的输出缓冲区

private Queue<String> __OutputBuffer = new Queue<String>();

定时器用于每100毫秒处理输出

new System.Timers.Timer()
{
    Interval = 100,
    Enabled = true
}.Elapsed += new ElapsedEventHandler(
    (caller, args) =>
    {
        ProcessOutput();
    }
);

处理队列

private void ProcessOutput()
{
    if (__OutputBuffer.Count > 0 && !String.IsNullOrEmpty(__OutputBuffer.Peek()))
    {
        object _Item = __OutputBuffer.Dequeue();

        if(_Item is String)
        {
            try
            {
                Browser.DocumentText += "<span style='font-family: Tahoma; font-size: 9pt;'>" + _Item + "</span>"; 
                //Exception On Line Above!
            }
            catch (Exception) { }
        }
    }
}   

添加到输出缓冲区的方法

private void UpdateOutput(String text)
{
    __OutputBuffer.Enqueue(text);
}

我收到了无效的强制转换异常,以下是获取异常时_Item的内容。

http://i.imgur.com/GddT1Jj.png

**以下引起异常...所以我怀疑它是队列中字符串的内容。

enter image description here

3 个答案:

答案 0 :(得分:2)

Queue<>不是线程安全的,而System.Timers.Timer在随机池线程上触发其事件。这就是调用ProcessOutput的位置,您可以在此处调用__OutputBuffer.Dequeue()并访问Browser.DocumentText

您可以使用__OutputBufferlockDequeue)保护Enqueue免受并发访问,或使用ConcurrentQueue。但是,您需要将Browser.DocumentText分配封送到UI线程,例如使用Control.InvokeControl.BeginInvoke

答案 1 :(得分:1)

正如Noseratio所说,Queue<>不是线程安全的,但如果您不希望在项目中使用锁定并且使用的是.NET 4.0或更新版本,则可以使用ConcurrentQueue<>类,即线程安全。

您需要进行一些更改,例如没有PeekDequeue方法,您必须使用TryPeekTryDequeue。但它不应该需要太多重大更改,它甚至可以让您进行一些优化,因为如果Queue为空,则两个try方法将返回false,因此您不再需要Count检查。

private void ProcessOutput()
{
    string output;
    if (__OutputBuffer.TryDequeue(out output) && !String.IsNullOrEmpty(output))
    {
        try
        {
            Browser.DocumentText += "<span style='font-family: Tahoma; font-size: 9pt;'>" + output  + "</span>"; 
        }
        catch (Exception) { } // <--- Blindly catching exceptsions is almost never the right thing to do.
    }
} 

答案 2 :(得分:0)

使用Timer被认为是多线程的。 你有一个新的线程每100毫秒,这可能会导致你出队的竞争条件

使用:

private ConcurrentQueue<String> __OutputBuffer = new ConcurrentQueue<String>();

private void ProcessOutput()
{
    string _Item;
    if (__OutputBuffer.TryDequeue(out _Item))
    {
         try
         {
              Browser.DocumentText += "<span style='font-family: Tahoma; font-size: 9pt;'>" + _Item + "</span>";
             //Exception On Line Above!
         }
         catch (Exception) { }
    }
}