Fine grained synchronization of a shared item list











up vote
1
down vote

favorite












I am using a thread-safe third party library to retrieve data from a historian.



The operating mode for a typical scenario is the following:



Library instance;

Result Process(string itemNames) {
var itemsIds = instance.ReserveItems(itemNames);
Result results = instance.ProcessItems(itemIds);
instance.ReleaseItems(itemIds);
return results;
}


Library is a class that is expensive to instantiate, so it is used here as a singleton (instance), and it works perfectly against multiple threads.



However, I notice sometimes that a Result is marked as failed ("item not found"), when multiple threads attempt to execute Process with an itemNames array that shares some common items. Because the library is very badly documented, that was unexpected.



By intensively logging, I have deduced that a thread could release an item at the same time another one is about to process it.



After a couple of mails to the library's vendor, I learnt that instance shares a list of reserved items between thread, and that it is necessary to synchronize the calls...



Uncompiling some part of the library confirmed this: there is a class level m_items list that is used by both ReserveItems and ReleaseItems.



So I envision the following waste:



Result Process(string itemNames) {
lock(instance) {
var itemsIds = instance.ReserveItems(itemNames);
Result results = instance.ProcessItems(itemIds);
instance.ReleaseItems(itemIds);
return results;
}
}


But it seems a bit too violent to me.



As this Library works perfectly when different items are processed by multiple thread, how can perform a more fine-grained synchronization and avoid a performance penalty?




EDIT - 2018-11-09



I noticed that the whole ProcessItems method body of the Library is enclosed into a lock statement...



So any attempt at fine synchronization around this is futile. I ended up enclosing my Process method body in a lock statement as well, the performance penalty is -as expected now- not perceptible at all.











share|improve this question




















  • 1




    this big lock(instance) is very rough. You are processing an array of items at once. This this batch-processing faster than iterating the items and calling "Reserve(singleitem); ProcessItems(singleitem); ReleaseItems(singleitem)" in a loop? If this has the same performance, then I would iterate the items and lock only the item, eg by having a threadsafe list of curretly processed items. If that sounds fine, I will post an answer with some code snippets, if you want.
    – gofal3
    Nov 8 at 8:48










  • Thanks for the idea, I will give this a try!
    – Larry
    Nov 8 at 8:53






  • 1




    You may also consider using ReaderWriterLockSlim. You can get a reader lock on ReserveItems and ProcessItems, release it and get a write lock to call ReleaseItems.
    – Nick
    Nov 8 at 9:16















up vote
1
down vote

favorite












I am using a thread-safe third party library to retrieve data from a historian.



The operating mode for a typical scenario is the following:



Library instance;

Result Process(string itemNames) {
var itemsIds = instance.ReserveItems(itemNames);
Result results = instance.ProcessItems(itemIds);
instance.ReleaseItems(itemIds);
return results;
}


Library is a class that is expensive to instantiate, so it is used here as a singleton (instance), and it works perfectly against multiple threads.



However, I notice sometimes that a Result is marked as failed ("item not found"), when multiple threads attempt to execute Process with an itemNames array that shares some common items. Because the library is very badly documented, that was unexpected.



By intensively logging, I have deduced that a thread could release an item at the same time another one is about to process it.



After a couple of mails to the library's vendor, I learnt that instance shares a list of reserved items between thread, and that it is necessary to synchronize the calls...



Uncompiling some part of the library confirmed this: there is a class level m_items list that is used by both ReserveItems and ReleaseItems.



So I envision the following waste:



Result Process(string itemNames) {
lock(instance) {
var itemsIds = instance.ReserveItems(itemNames);
Result results = instance.ProcessItems(itemIds);
instance.ReleaseItems(itemIds);
return results;
}
}


But it seems a bit too violent to me.



As this Library works perfectly when different items are processed by multiple thread, how can perform a more fine-grained synchronization and avoid a performance penalty?




EDIT - 2018-11-09



I noticed that the whole ProcessItems method body of the Library is enclosed into a lock statement...



So any attempt at fine synchronization around this is futile. I ended up enclosing my Process method body in a lock statement as well, the performance penalty is -as expected now- not perceptible at all.











share|improve this question




















  • 1




    this big lock(instance) is very rough. You are processing an array of items at once. This this batch-processing faster than iterating the items and calling "Reserve(singleitem); ProcessItems(singleitem); ReleaseItems(singleitem)" in a loop? If this has the same performance, then I would iterate the items and lock only the item, eg by having a threadsafe list of curretly processed items. If that sounds fine, I will post an answer with some code snippets, if you want.
    – gofal3
    Nov 8 at 8:48










  • Thanks for the idea, I will give this a try!
    – Larry
    Nov 8 at 8:53






  • 1




    You may also consider using ReaderWriterLockSlim. You can get a reader lock on ReserveItems and ProcessItems, release it and get a write lock to call ReleaseItems.
    – Nick
    Nov 8 at 9:16













up vote
1
down vote

favorite









up vote
1
down vote

favorite











I am using a thread-safe third party library to retrieve data from a historian.



The operating mode for a typical scenario is the following:



Library instance;

Result Process(string itemNames) {
var itemsIds = instance.ReserveItems(itemNames);
Result results = instance.ProcessItems(itemIds);
instance.ReleaseItems(itemIds);
return results;
}


Library is a class that is expensive to instantiate, so it is used here as a singleton (instance), and it works perfectly against multiple threads.



However, I notice sometimes that a Result is marked as failed ("item not found"), when multiple threads attempt to execute Process with an itemNames array that shares some common items. Because the library is very badly documented, that was unexpected.



By intensively logging, I have deduced that a thread could release an item at the same time another one is about to process it.



After a couple of mails to the library's vendor, I learnt that instance shares a list of reserved items between thread, and that it is necessary to synchronize the calls...



Uncompiling some part of the library confirmed this: there is a class level m_items list that is used by both ReserveItems and ReleaseItems.



So I envision the following waste:



Result Process(string itemNames) {
lock(instance) {
var itemsIds = instance.ReserveItems(itemNames);
Result results = instance.ProcessItems(itemIds);
instance.ReleaseItems(itemIds);
return results;
}
}


But it seems a bit too violent to me.



As this Library works perfectly when different items are processed by multiple thread, how can perform a more fine-grained synchronization and avoid a performance penalty?




EDIT - 2018-11-09



I noticed that the whole ProcessItems method body of the Library is enclosed into a lock statement...



So any attempt at fine synchronization around this is futile. I ended up enclosing my Process method body in a lock statement as well, the performance penalty is -as expected now- not perceptible at all.











share|improve this question















I am using a thread-safe third party library to retrieve data from a historian.



The operating mode for a typical scenario is the following:



Library instance;

Result Process(string itemNames) {
var itemsIds = instance.ReserveItems(itemNames);
Result results = instance.ProcessItems(itemIds);
instance.ReleaseItems(itemIds);
return results;
}


Library is a class that is expensive to instantiate, so it is used here as a singleton (instance), and it works perfectly against multiple threads.



However, I notice sometimes that a Result is marked as failed ("item not found"), when multiple threads attempt to execute Process with an itemNames array that shares some common items. Because the library is very badly documented, that was unexpected.



By intensively logging, I have deduced that a thread could release an item at the same time another one is about to process it.



After a couple of mails to the library's vendor, I learnt that instance shares a list of reserved items between thread, and that it is necessary to synchronize the calls...



Uncompiling some part of the library confirmed this: there is a class level m_items list that is used by both ReserveItems and ReleaseItems.



So I envision the following waste:



Result Process(string itemNames) {
lock(instance) {
var itemsIds = instance.ReserveItems(itemNames);
Result results = instance.ProcessItems(itemIds);
instance.ReleaseItems(itemIds);
return results;
}
}


But it seems a bit too violent to me.



As this Library works perfectly when different items are processed by multiple thread, how can perform a more fine-grained synchronization and avoid a performance penalty?




EDIT - 2018-11-09



I noticed that the whole ProcessItems method body of the Library is enclosed into a lock statement...



So any attempt at fine synchronization around this is futile. I ended up enclosing my Process method body in a lock statement as well, the performance penalty is -as expected now- not perceptible at all.








c# multithreading thread-synchronization






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 2 days ago

























asked Nov 8 at 8:34









Larry

12.9k75387




12.9k75387








  • 1




    this big lock(instance) is very rough. You are processing an array of items at once. This this batch-processing faster than iterating the items and calling "Reserve(singleitem); ProcessItems(singleitem); ReleaseItems(singleitem)" in a loop? If this has the same performance, then I would iterate the items and lock only the item, eg by having a threadsafe list of curretly processed items. If that sounds fine, I will post an answer with some code snippets, if you want.
    – gofal3
    Nov 8 at 8:48










  • Thanks for the idea, I will give this a try!
    – Larry
    Nov 8 at 8:53






  • 1




    You may also consider using ReaderWriterLockSlim. You can get a reader lock on ReserveItems and ProcessItems, release it and get a write lock to call ReleaseItems.
    – Nick
    Nov 8 at 9:16














  • 1




    this big lock(instance) is very rough. You are processing an array of items at once. This this batch-processing faster than iterating the items and calling "Reserve(singleitem); ProcessItems(singleitem); ReleaseItems(singleitem)" in a loop? If this has the same performance, then I would iterate the items and lock only the item, eg by having a threadsafe list of curretly processed items. If that sounds fine, I will post an answer with some code snippets, if you want.
    – gofal3
    Nov 8 at 8:48










  • Thanks for the idea, I will give this a try!
    – Larry
    Nov 8 at 8:53






  • 1




    You may also consider using ReaderWriterLockSlim. You can get a reader lock on ReserveItems and ProcessItems, release it and get a write lock to call ReleaseItems.
    – Nick
    Nov 8 at 9:16








1




1




this big lock(instance) is very rough. You are processing an array of items at once. This this batch-processing faster than iterating the items and calling "Reserve(singleitem); ProcessItems(singleitem); ReleaseItems(singleitem)" in a loop? If this has the same performance, then I would iterate the items and lock only the item, eg by having a threadsafe list of curretly processed items. If that sounds fine, I will post an answer with some code snippets, if you want.
– gofal3
Nov 8 at 8:48




this big lock(instance) is very rough. You are processing an array of items at once. This this batch-processing faster than iterating the items and calling "Reserve(singleitem); ProcessItems(singleitem); ReleaseItems(singleitem)" in a loop? If this has the same performance, then I would iterate the items and lock only the item, eg by having a threadsafe list of curretly processed items. If that sounds fine, I will post an answer with some code snippets, if you want.
– gofal3
Nov 8 at 8:48












Thanks for the idea, I will give this a try!
– Larry
Nov 8 at 8:53




Thanks for the idea, I will give this a try!
– Larry
Nov 8 at 8:53




1




1




You may also consider using ReaderWriterLockSlim. You can get a reader lock on ReserveItems and ProcessItems, release it and get a write lock to call ReleaseItems.
– Nick
Nov 8 at 9:16




You may also consider using ReaderWriterLockSlim. You can get a reader lock on ReserveItems and ProcessItems, release it and get a write lock to call ReleaseItems.
– Nick
Nov 8 at 9:16












1 Answer
1






active

oldest

votes

















up vote
1
down vote



accepted










You could implement a lock per item ID. That could take the form of a Dictionary<string, object> where the value is the lock object (new object()).



If you want to process the same item ID on multiple threads at the same time without blocking everything in case of conflict, you could track more state in the dictionary value to do that. As an example, you could use a Dictionary<string, Lazy<Result>>. The first thread to need an item ID would initialize and directly consume the lazy. Other threads can then detect that an operation is in progress on that item ID and also consume the lazy.






share|improve this answer

















  • 1




    Even if this is no longer useful in my case, I believe this is the right path. Thanks a lot for the pointer!
    – Larry
    2 days ago











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














 

draft saved


draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53204009%2ffine-grained-synchronization-of-a-shared-item-list%23new-answer', 'question_page');
}
);

Post as a guest
































1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
1
down vote



accepted










You could implement a lock per item ID. That could take the form of a Dictionary<string, object> where the value is the lock object (new object()).



If you want to process the same item ID on multiple threads at the same time without blocking everything in case of conflict, you could track more state in the dictionary value to do that. As an example, you could use a Dictionary<string, Lazy<Result>>. The first thread to need an item ID would initialize and directly consume the lazy. Other threads can then detect that an operation is in progress on that item ID and also consume the lazy.






share|improve this answer

















  • 1




    Even if this is no longer useful in my case, I believe this is the right path. Thanks a lot for the pointer!
    – Larry
    2 days ago















up vote
1
down vote



accepted










You could implement a lock per item ID. That could take the form of a Dictionary<string, object> where the value is the lock object (new object()).



If you want to process the same item ID on multiple threads at the same time without blocking everything in case of conflict, you could track more state in the dictionary value to do that. As an example, you could use a Dictionary<string, Lazy<Result>>. The first thread to need an item ID would initialize and directly consume the lazy. Other threads can then detect that an operation is in progress on that item ID and also consume the lazy.






share|improve this answer

















  • 1




    Even if this is no longer useful in my case, I believe this is the right path. Thanks a lot for the pointer!
    – Larry
    2 days ago













up vote
1
down vote



accepted







up vote
1
down vote



accepted






You could implement a lock per item ID. That could take the form of a Dictionary<string, object> where the value is the lock object (new object()).



If you want to process the same item ID on multiple threads at the same time without blocking everything in case of conflict, you could track more state in the dictionary value to do that. As an example, you could use a Dictionary<string, Lazy<Result>>. The first thread to need an item ID would initialize and directly consume the lazy. Other threads can then detect that an operation is in progress on that item ID and also consume the lazy.






share|improve this answer












You could implement a lock per item ID. That could take the form of a Dictionary<string, object> where the value is the lock object (new object()).



If you want to process the same item ID on multiple threads at the same time without blocking everything in case of conflict, you could track more state in the dictionary value to do that. As an example, you could use a Dictionary<string, Lazy<Result>>. The first thread to need an item ID would initialize and directly consume the lazy. Other threads can then detect that an operation is in progress on that item ID and also consume the lazy.







share|improve this answer












share|improve this answer



share|improve this answer










answered Nov 8 at 14:03









usr

142k25184297




142k25184297








  • 1




    Even if this is no longer useful in my case, I believe this is the right path. Thanks a lot for the pointer!
    – Larry
    2 days ago














  • 1




    Even if this is no longer useful in my case, I believe this is the right path. Thanks a lot for the pointer!
    – Larry
    2 days ago








1




1




Even if this is no longer useful in my case, I believe this is the right path. Thanks a lot for the pointer!
– Larry
2 days ago




Even if this is no longer useful in my case, I believe this is the right path. Thanks a lot for the pointer!
– Larry
2 days ago


















 

draft saved


draft discarded



















































 


draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53204009%2ffine-grained-synchronization-of-a-shared-item-list%23new-answer', 'question_page');
}
);

Post as a guest




















































































Popular posts from this blog

Landwehr

Reims

Schenkenzell