如何在 C# 中锁定一个整数?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/781189/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to lock on an integer in C#?
提问by Waleed Eissa
Is there any way to lock on an integer in C#? Integers can not be used with lock because they are boxed (and lock only locks on references).
有没有办法在 C# 中锁定整数?整数不能与锁定一起使用,因为它们是装箱的(并且锁定仅锁定引用)。
The scenario is as follows: I have a forum based website with a moderation feature. What I want to do is make sure that no more than one moderator can moderate a post at any given time. To achieve this, I want to lock on the ID of the post.
场景如下: 我有一个基于论坛的网站,具有审核功能。我想要做的是确保在任何给定时间,只有一位版主可以审核帖子。为此,我想锁定帖子的 ID。
I've had a couple of ideas so far (e.g. using a dictionary<int, object>), but I'm looking for a better and cleaner way.
到目前为止,我已经有了一些想法(例如,使用字典<int, object>),但我正在寻找一种更好更简洁的方法。
Any suggestions?
有什么建议?
回答by Konrad Rudolph
Why don't you lock on the whole posting instead just on its ID?
为什么不锁定整个帖子,而只锁定其 ID?
回答by Greg Beech
If it's a website then using an in-process lock probably isn't the best approach as if you need to scale the site out onto multiple servers, or add another site hosting an API (or anything else that would require another process accessing the same data to exist) then all your locking strategies are immediately ineffective.
如果它是一个网站,那么使用进程内锁可能不是最好的方法,就像您需要将站点扩展到多台服务器,或添加另一个托管 API 的站点(或其他任何需要另一个进程访问相同数据存在)那么您所有的锁定策略立即无效。
I'd be inclined to look into database-based locking for this. The simplest approach is to use optimistic locking with something like a timestamp of when the post was last updated, and to reject updates made to a post unless the timestamps match.
我倾向于为此研究基于数据库的锁定。最简单的方法是使用乐观锁和类似帖子最后更新时间的时间戳,并拒绝对帖子所做的更新,除非时间戳匹配。
回答by rguerreiro
You should use a sync object like this:
您应该使用这样的同步对象:
public class YourForm
{
private static object syncObject = new object();
public void Moderate()
{
lock(syncObject)
{
// do your business
}
}
}
But this approach shouldn't be used in a web app scenario.
但是这种方法不应该用在 Web 应用程序场景中。
回答by Pontus Gagge
I doubt you should use a database or O/S level feature such as locks for a business level decision. Locks incur significant overheads when held for long times (and in these contexts, anything beyond a couple of hundred milliseconds is an eternity).
我怀疑您是否应该使用数据库或 O/S 级别的功能(例如锁)来进行业务级别的决策。长时间持有锁会产生大量开销(在这些情况下,超过几百毫秒的任何事情都是永恒的)。
Add a status field to the post. If you deal with several therads directly, then you can use O/S level locks -- to set the flag.
向帖子添加状态字段。如果您直接处理多个 therad,那么您可以使用 O/S 级别锁——来设置标志。
回答by LukeH
I would personally go with either Greg'sor Konrad'sapproach.
If you really do want to lock
against the post ID itself (and assuming that your code will only ever be running in a single process) then something like this isn't toodirty:
如果你确实想lock
对帖子的ID本身(并假设您的代码将永远只能在一个进程中运行),那么这样的事情是不是太肮脏:
public class ModeratorUtils
{
private static readonly HashSet<int> _LockedPosts = new HashSet<int>();
public void ModeratePost(int postId)
{
bool lockedByMe = false;
try
{
lock (_LockedPosts)
{
lockedByMe = _LockedPosts.Add(postId);
}
if (lockedByMe)
{
// do your editing
}
else
{
// sorry, can't edit at this time
}
}
finally
{
if (lockedByMe)
{
lock (_LockedPosts)
{
_LockedPosts.Remove(postId);
}
}
}
}
}
回答by configurator
I like doing it like this
我喜欢这样做
public class Synchronizer {
private Dictionary<int, object> locks;
private object myLock;
public Synchronizer() {
locks = new Dictionary<int, object>();
myLock = new object();
}
public object this[int index] {
get {
lock (myLock) {
object result;
if (locks.TryGetValue(index, out result))
return result;
result = new object();
locks[index] = result;
return result;
}
}
}
}
Then, to lock on an int you simply (using the same synchronizer every time)
然后,简单地锁定一个 int(每次使用相同的同步器)
lock (sync[15]) { ... }
This class returns the same lock object when given the same index twice. When a new index comes, it create an object, returning it, and stores it in the dictionary for next times.
当给定相同的索引两次时,该类返回相同的锁对象。当新索引到来时,它会创建一个对象,返回它,并将其存储在字典中以备下次使用。
It can easily be changed to work generically with any struct
or value type, or to be static
so that the synchronizer object does not have to be passed around.
可以很容易地将其更改为与 anystruct
或 value 类型通用,或者static
不必传递同步器对象。
回答by Lasse V. Karlsen
You need a whole different approach to this.
你需要一个完全不同的方法来解决这个问题。
Remember that with a website, you don't actually have a live running application on the other side that responds to what the user does.
请记住,对于网站,您实际上并没有在另一端实时运行的应用程序来响应用户的操作。
You basically start a mini-app, which returns the web-page, and then the server is done. That the user ends up sending some data back is a by-product, not a guarantee.
您基本上启动了一个小应用程序,它返回网页,然后服务器就完成了。用户最终发回一些数据是副产品,而不是保证。
So, you need to lock to persist after the application has returned the moderation page back to the moderator, and then release it when the moderator is done.
因此,您需要在应用程序将审核页面返回给主持人后锁定以保持不变,然后在主持人完成后释放它。
And you need to handle some kind of timeout, what if the moderator closes his browser after getting the moderation page back, and thus never communicates back with the server that he/she is done with the moderation process for that post.
并且您需要处理某种超时,如果主持人在获得审核页面后关闭他的浏览器,因此永远不会与服务器通信他/她已完成该帖子的审核过程,该怎么办。
回答by Sam Saffron
Ideally you can avoid all the complex and brittle C# locking and replace it with database locking, if your transactions are designed correctly then you should be able to get by with DB transactions only.
理想情况下,您可以避免所有复杂而脆弱的 C# 锁定,并将其替换为数据库锁定,如果您的事务设计正确,那么您应该只能使用 DB 事务。
回答by Joe
Two boxed integers that happen to have the same value are completely indepent objects. So if you wanted to do this, your idea of Dictionary would probably be the way to go. You'd need to synchronize access to the dictionary to make sure you are always getting the same instance. And you'd have the problem of the dictionary growing in size.
碰巧具有相同值的两个装箱整数是完全独立的对象。因此,如果您想这样做,那么您对 Dictionary 的想法可能是正确的选择。您需要同步对字典的访问,以确保始终获得相同的实例。你会遇到字典变大的问题。
回答by Omar Kooheji
C# locking is for thread safety and doesn't work the way you want it to for web applications.
C# 锁定是为了线程安全,对于 Web 应用程序,它不能按照您希望的方式工作。
The simplest solution is adding a column to the table that you want to lock and when somone locks it write to the db that that column is locked.
最简单的解决方案是向要锁定的表中添加一列,当有人锁定时,它会写入该列已锁定的数据库。
Dont let anyone open a post in edit mode if the column is locked for editing.
如果该列被锁定以进行编辑,则不要让任何人在编辑模式下打开帖子。
Otherwise maintain a static list of locked entry Ids and compare to that before allowing an edit.
否则,维护一个锁定条目 ID 的静态列表,并在允许编辑之前与该列表进行比较。