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
ProcessItemsmethod 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
Processmethod body in a lock statement as well, the performance penalty is -as expected now- not perceptible at all.
c# multithreading thread-synchronization
add a comment |
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
ProcessItemsmethod 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
Processmethod body in a lock statement as well, the performance penalty is -as expected now- not perceptible at all.
c# multithreading thread-synchronization
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
add a comment |
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
ProcessItemsmethod 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
Processmethod body in a lock statement as well, the performance penalty is -as expected now- not perceptible at all.
c# multithreading thread-synchronization
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
ProcessItemsmethod 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
Processmethod body in a lock statement as well, the performance penalty is -as expected now- not perceptible at all.
c# multithreading thread-synchronization
c# multithreading thread-synchronization
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
add a comment |
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
add a comment |
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.
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
add a comment |
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.
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
add a comment |
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.
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
add a comment |
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.
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.
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
add a comment |
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
add a comment |
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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