There was a need: to restrict access to the object (only one thread can use it). Ie only one stream can use methods and methods of its objects. Sample code (method call).

var human=new Human("Dima"); var ts=new Task(human.Coat("2").Sleeve.Right.Cut); ts.Start(); 

Ie I create a person with the name "Dima" and say: man, cut off the right sleeve of the second coat. Moreover, the Coat method refers to the Coats collection for a while, that is, Human has collections of empty Coats. When referring to this method, we pass the coat ID and continue to work with it. We send requests to the site.

The hitch is that all this will take place in a multi-thread, that is, I can call 4 similar methods and pull a random Coat from the array. If he is busy with some thread (for example, I called Cut ()), then he waits until the stream runs. After working out Coat is cleared (more precisely, the identifier) ​​and ready to use.

I tried to make the lock operator on the Coat returned from the collection (in the form of a locker), but this is stupid, because it returns this object and doesn't care. I tried to create a flag, but in a multithreading garbage turned out. I tried a couple of ways, but I don’t remember them and they are as stupid as these.

I think to do so:

 var human=new Human("Dima"); Coat coat; lock (coat=human.Coat("2")) { var ts=new Task(human.Coat("2").Sleeve.Right.Cut); ts.Start; } 

And further, when initializing objects (for example, the Sleeve), to transfer this coat and insert lock in each method, but it smacks it with a bicycle on a crutch, ... I feel that in theory I miss a very important point, but which one.

Question: how to do such a thing? Is it possible? Is my method suitable and how do you usually do this?

PS An example of an abstract, vital code can not show.


Update

Thinking on the method above, I realized that again it was not correct. If I set up lock (coat) everywhere, then ...

Initialize the variable Sleeve and pass Coat

 _ sleeve=new Sleeve(this); Lock на этот Sleeve private SleeveClass _sleeve; public SleeveClass Sleeve { get { lock (this) { return _sleeve; } } } 

Same with Right

Cut method

 public void Cut() { lock (_сoat) { Console.WriteLine(String.Format("Coat {0}",_сoat.CoatId)); } } 

It can happen like this: there are two streams, one waits somewhere on a change in Coat data. For example here: public CoatClass Coat (string CoatId) {

  lock (CoatObj) { CoatClass CoatObj; _coatPull.TryPeek(out CoatObj); CoatObj.CoatId = CoatId; return CoatObj; } } 

And the other is in the Cut method. The Coat object may first change in one thread, give the signal "worked", and then the Cut will work and in the end we will cut off the wrong coat. Therefore, this option is not suitable, you need to continuously block access to objects and fields, it is busy with some kind of stream.


I use Concurrent collection. Yes, it is thread-safe, but the essence is different there (as far as I understood). A frequent problem when working with a collection in multithreading is the simultaneous recording and deletion of the same object. And this collection just gives access to only one thread, which solves this problem (and several others). Unlike the others, the collection produces a random element. Tobish all collections solve the problem of working with her, and not with the elements of the collection.

  • one
    "Multithreading" on your client or server? If the client - then why? - Pavel Mayorov 2:32
  • @Pavel Mayorov work happens with the site was wrong. - Arantler 2:49
  • one
    So where is the multithread? - Pavel Mayorov
  • @Pavel Mayorov corrected - Arantler
  • @Pavel Mayorov thanks for responding. - Arantler

1 answer 1

Do you need an exclusive right to own an object? This is a dangerous, dangerous undertaking that could lead to a deadlock. From the point of view of OOP, your code is somewhat not logical. Your say: the right sleeve of the second coat of Dima - cut off. And should: Dima, cut off the right sleeve of the second coat. The object does not need to know which collection it is in. You can use a double-check lock . Below is a simple example.

 public void DoWork() { //Your code goes here Task.Factory.StartNew(() => { var coat = human.Coar("2"); if (!coat.SetOwner(human)) return; // some logic coat.SetOwner(null); }); } public class Human { //your code here } public class Coat { public Human Owner {get; private set; } private object _lockObject = new object(); public bool SetOwner(Human owner) { if (Owner != null) return false; lock(_lockObject) { if (Owner != null) return false; Owner = owner; return true; } } } 
  • In this case, the code seems to work the same way ... And my version of the translation is probably in vain. And how can you use this? Put the flag on User (not used) and if used, then try again? You can enable the flag in User, but in all subsequent methods at the end you need to set the flag to be reversed ... - Arantler
  • one
    Example - Markeli
  • And in each required method of accessing the object, to transmit a reference to the one who calls it, and inside to make a check whether it has the right to do it now. - Markeli
  • There is already a reputation, but the answer seems to be quite good. You should transfer the code from the gist to the response itself, it will be released quite well. - Nick Volynkin
  • @NickVolynkin, done. - Markeli