C# 访问由另一个线程添加的字典项

C# 访问由另一个线程添加的字典项,c#,wpf,multithreading,C#,Wpf,Multithreading,这是我的密码- public partial class MainWindow : Window { ConcurrentDictionary<int,BitmapSource> Cache = new ConcurrentDictionary<int,BitmapSource>(5, 199); int width = 720; int height = 480; int stride = (width * 3 / 4 ) * 4 +

这是我的密码-

public partial class MainWindow : Window
{
    ConcurrentDictionary<int,BitmapSource> Cache = new ConcurrentDictionary<int,BitmapSource>(5, 199);

    int width = 720;
    int height = 480;
    int stride = (width * 3 / 4 ) * 4 + 4;
    int currentframe = 0;
    public MainWindow()
    {
        InitializeComponent();
        Thread t = new Thread(() =>
        {
            while (true)
            {
                for (int i = -9; i < 9; i++)
                {
                    if (!Cache.ContainsKey(currentframe + i))
                    {
                        RenderFrameToCache(currentframe + i);
                    }
                }
                Thread.Sleep(500);
            }
        });
        t.Start();
    }
    private object locker = new object();
    private void RenderFrameToCache(int frame)
    {
            byte[] pixels;
            //Create byte array
            BitmapSource img = BitmapSource.Create(width, height, 96, 96, PixelFormats.Bgr24, null, pixels, stride);
            Cache.AddOrUpdate(frame, img, (x,y) => img);
    }

    private BitmapSource GetBmpSource(int frame)
    {
        if (Cache.ContainsKey(frame))
        {
            return Cache[frame];
        }
        else
        {
            RenderFrameToCache(frame);
            return Cache[frame];
        }
    }

    private void TextBox_LostFocus(object sender, RoutedEventArgs e)
    {            
        Cache.Clear();
        image.Source = new BitmapImage();
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        currentframe++;
        image.Source = GetBmpSource(currentframe);

    }

    private void Button_Click_1(object sender, RoutedEventArgs e)
    {
        currentframe--;
        image.Source = GetBmpSource(currentframe);

    }
}
公共部分类主窗口:窗口
{
ConcurrentDictionary缓存=新的ConcurrentDictionary(5199);
整数宽度=720;
内部高度=480;
步幅=(宽度*3/4)*4+4;
int currentframe=0;
公共主窗口()
{
初始化组件();
线程t=新线程(()=>
{
while(true)
{
for(int i=-9;i<9;i++)
{
如果(!Cache.ContainsKey(currentframe+i))
{
RenderFrameToCache(当前帧+i);
}
}
睡眠(500);
}
});
t、 Start();
}
私有对象锁定器=新对象();
私有void RenderFrameToCache(int-frame)
{
字节[]像素;
//创建字节数组
BitmapSource img=BitmapSource.Create(宽度、高度、96、96、PixelFormats.Bgr24、null、像素、步幅);
AddOrUpdate(帧,img,(x,y)=>img);
}
私有位图源GetBmpSource(int帧)
{
if(Cache.ContainsKey(帧))
{
返回缓存[帧];
}
其他的
{
RenderFrameToCache(框架);
返回缓存[帧];
}
}
私有void文本框\u LostFocus(对象发送方,RoutedEventArgs e)
{            
Cache.Clear();
image.Source=新的BitmapImage();
}
私有无效按钮\u单击(对象发送者,路由目标e)
{
currentframe++;
image.Source=GetBmpSource(当前帧);
}
私有无效按钮\u单击\u 1(对象发送者,路由目标)
{
当前帧--;
image.Source=GetBmpSource(当前帧);
}
}
第二个线程应该用项目填充字典,这样当窗口想要显示它们时,它们就在手边。
无论何时按下按钮,都会出现InvalidOperationException。问题出在哪里?

使用线程安全
ConcurrentDictionary

发件人:

所有这些操作[TryAdd,TryUpdate,…]都是原子操作,并且对于 ConcurrentDictionary类上的所有其他操作。 […]对于字典的修改和写入操作, ConcurrentDictionary使用细粒度锁定来确保 线程安全。(字典上的读取操作在 无锁方式。)

我解决了这个问题。 我必须使用BitmapSource。每次添加新的BitmapSource时都要冻结。
这个链接解释了这一点-

显示了您用来读取字典中的值的代码。您正在进行数据竞争。在另一个线程上阅读元素时,不能将元素添加到词典中。一次读取多个线程是可以的,但是写入需要独占访问。在additem()中,我在添加项的代码周围有一个lock语句,但它不起作用。这就是我应该做的吗?请问一个问题,
dict.ContainsKey(key)
中的
key
来自哪里?您的代码中缺少太多东西,我们无法找出您的问题所在。你还说你试过使用并发字典,有效吗?你有没有遇到同样的错误,你有没有遇到新的错误?错误发生在哪一行?我已经编辑了这个问题。希望现在更清楚了。不幸的是,这不起作用。如果我有什么不清楚的地方,请告诉我。@phil你能在使用ConcurrentDictionary但不起作用的地方发布代码吗?@phil我打赌我们丢失了一些代码。请发布整个代码或创建一个产生错误的简单测试用例。我做了一个快速而肮脏的测试,无法生成您的错误。