我有一个我用C#编写的应用程序,虽然这里适用任何类似的语言。
应用程序的工作是根据通过各种UDP和TCP套接字接收的数据,实时将图形场景绘制到窗体上的窗口。每个UDP和TCP连接使用自己的线程:这些线程各自修改内存中的各种对象,这些对象又修改图形显示。我还有一个用户界面线程,它能够接收用户事件(按钮点击等),然后修改那些相同的对象和显示。最后,我还有许多定时器,我发射它们自己的线程,修改那些相同的对象和显示。
正在修改的内存中的对象由大约15个不同的类组成。
一切都非常可靠,但是所有这些不同的类都被不同的线程修改,我不得不添加很多同步锁。我必须分别查看每个类,以确定哪个内存可能被多个线程更改。
在这种情况下似乎很容易错过其中一个点:忘记在需要的地方添加同步。
我很好奇其他人是否会按照我的方式实现这一点,或者是否有一些更优雅的方式:或许以某种方式将A类的所有修改都放在自己的线程或其他东西上?
(PS我在第一次事情没有那么顺利的时候害怕在这里问一个问题。但我不认为我的问题在这里是非常明显的,所以我希望你也不会。; o)
答案 0 :(得分:1)
我认为没有直截了当的答案。
我帮助其他人改变设计以应对类似的情况。最常用的技术之一是引入更好的抽象。
例如,假设您有多个线程需要更新包含用户的Map,而另一个包含活动用户的Set,而不是拥有用户地图和活动用户集的锁,并让您的线程手动获取锁,I& #39; ll建议引入一个抽象调用UserRepository,其中包含User map和Active User Set。 UserRepository将为其他人提供一些商业上有意义的方法来操纵UserRepository。锁是在UserRepository的方法中获取的,而不是由调用者显式获取。
根据我过去的经验,通过更好的设计(如上述示例),可以大大简化80%以上的复杂同步。
还有其他技术可行。例如,如果更新可以异步执行,而不是让线程直接更新资源,则可以创建命令对象并放入生产者 - 消费者队列,并使用专用线程执行更新。
有时,处理更少的锁更容易。例如,在更新多个资源时,我们可以将更新视为一个完整的操作,而不是对每个资源使用一个锁,而只使用一个锁来进行线程之间的协调。当然它会增加争用,但有些情况下争用不是一个大问题,但我们需要可维护性。
我相信有很多其他方法可以处理类似情况,我只是分享我以前的一些经验(有效:P)