C# can I lock a method parameter?
We have a class variable ArrayList binaryScanData
in a class. In all methods having access to it, we put lock(binaryScanData)
on it because it is shared. Now we want to move one of those methods out to another util class to make it a static
method. We will pass that binaryScanData
into 开发者_高级运维the method like this:
public static void convertAndSaveRawData(ref MemoryStream output, ref ArrayList binaryScanData)
Our questions are followed:
- how can we sychoronize that
binaryScanData
? can we do the same as it is originally? ref
is necessary? It will only be read in thatconvertAndSaveRawData
method.
The ref isn't necessary, it is only needed if you are going to change the reference itself (ie, assign a new list to it). You can still lock on the object if you like. I recommend locking on SyncRoot
, which I'm not sure if ArrayList has. If not, you might consider moving up to List<T>
.
You don't need to make it a ref
parameter unless you write binaryScanData = something
.
You can lock on the parameter the same way you lock on anything else.
The C# lock
keyowrd locks on an object instance; it doesn't matter what the instance came from.
This sounds very wrong. I can imagine that your class objects share a single ArrayList instance and that therefore code that accesses it needs to be synchronized. But that would make the ArrayList object reference static as well, why do you have to pass it as an argument?
If other code needs to call this static method without having to use a reference to your class object then they'd probably have to pass their own instance of the ArrayList. Then it doesn't make sense anymore that you would need to lock. The calling code needs to take care of locking. Only it knows in what other places that particular ArrayList object gets used.
Sorry, I can't make much sense of it. That starts by you using the ArrayList object as the lock argument. You can't lock data, you can only lock code that uses data.
- how can we sychoronize that binaryScanData? can we do the same as it is originally?
By locking the same object instance from every piece of code that requires synchronization.
Note that this does not necessarily imply locking the same object you're modifying. In fact, that's dangerous and considered bad practice. It leaves you susceptible to deadlocks and other nastiness because some other code could lock the same object. You're best off creating your own, private object and using that for synchronization.
- ref is necessary? It will only be read in that convertAndSaveRawData method.
No, it's not. You've got two entirely different concepts mixed up.
You can create a synchronized wrapper to an existing ArrayList that internally locks on all get/sets:
ArrayList unsyncList = new ArrayList();
ArrayList syncWrapperList = ArrayList.Synchronized(unsyncList);
There is a perf cost to the locking, so only use the wrapper where you must synchronize every call.
ref
isn't needed for either parameter as both will be passed by reference anyway, as they are reference types.
As has been pointed out, ArrayList
is not recommended as a way of holding a list of items anymore, as it often requires boxing and is therefore usually a lot slower. Try List<T>
instead unless you are using 1.1
Those two points don't answer you're main question though: to synchronise a list is not a trivial task, as the .NET implementation is not thread safe. You can see a whole discussion on it: Why is C# List<> not thread-safe? You can synchronise the list inside your own class, but it could still be altered outside of that class.
One technique, if you have created the list yourself, is to make it a read-only list, and provide methods to add to it by subclassing List<T>
or IList<T>
.
This ThreadSafe List article attempts to make a generic thread-safe list, but if you read the comments at the bottom of the page it still has shortcomings.
精彩评论