Remoting and Threadsafe access
-
I have a common design problem that I'm sure many have already encountered. I have a system where any number of ASP clients will be submitting requests that eventually are stored in a SQL Server. I need to generate unique request IDs, but I cannot use a simple autoinc field in the request table (it's kind of a long story). Instead I need to generate a unique integer for each request that will then be used to format a more complex unique string that becomes the final request ID. Obviously I could store a counter in the database, but I am pretty certain this is the slowest method, although I am not positive because I am not really sure how much overhead is involved in making a Remoting call. In any case, my db will be working pretty hard on more important stuff, so I would prefer not to add another call. What I think is a more efficient approach is to create a simple component that is accessed by Remoting and returns a unique incremented counter to each request. But I do not have a lot of experience with NET Remoting and I have not found that the MSDN adequately explains thread safety issues. So my question is what is the best way to ensure threadsafe access to the counter value? InterlockedIncrement is always atomic and inherently threadsafe, but that in itself only gurantees the increment operation is threadsafe, but does not guarantee that the subsequent return of the value will not be subject to possible re-entrance errors. A Mutex does not guarantee the entire method call will be atomic, but it does guarantee the entire method call will be threadsafe. So I know that will work. But using a mutex results in at least a couple of context switches which is probably not a big deal, but I would like to try something with a little less overhead since all I need is a simple unique integer. So I have been thinking of using a CriticalSection (aka SyncLock) because those involve less system overhead. If you have a lot of experience with threading, however, you will understand my concern. CriticalSections appear to be simple but in fact are much more subtle than many developers really understand. Without knowing much of anything about how NET Remoting manages it's threads, I am a little reluctant to trust that a SyncLock will actually always be working the way I want it to. Anyone have any real experience with this issue? TIA Robert
-
I have a common design problem that I'm sure many have already encountered. I have a system where any number of ASP clients will be submitting requests that eventually are stored in a SQL Server. I need to generate unique request IDs, but I cannot use a simple autoinc field in the request table (it's kind of a long story). Instead I need to generate a unique integer for each request that will then be used to format a more complex unique string that becomes the final request ID. Obviously I could store a counter in the database, but I am pretty certain this is the slowest method, although I am not positive because I am not really sure how much overhead is involved in making a Remoting call. In any case, my db will be working pretty hard on more important stuff, so I would prefer not to add another call. What I think is a more efficient approach is to create a simple component that is accessed by Remoting and returns a unique incremented counter to each request. But I do not have a lot of experience with NET Remoting and I have not found that the MSDN adequately explains thread safety issues. So my question is what is the best way to ensure threadsafe access to the counter value? InterlockedIncrement is always atomic and inherently threadsafe, but that in itself only gurantees the increment operation is threadsafe, but does not guarantee that the subsequent return of the value will not be subject to possible re-entrance errors. A Mutex does not guarantee the entire method call will be atomic, but it does guarantee the entire method call will be threadsafe. So I know that will work. But using a mutex results in at least a couple of context switches which is probably not a big deal, but I would like to try something with a little less overhead since all I need is a simple unique integer. So I have been thinking of using a CriticalSection (aka SyncLock) because those involve less system overhead. If you have a lot of experience with threading, however, you will understand my concern. CriticalSections appear to be simple but in fact are much more subtle than many developers really understand. Without knowing much of anything about how NET Remoting manages it's threads, I am a little reluctant to trust that a SyncLock will actually always be working the way I want it to. Anyone have any real experience with this issue? TIA Robert
-
No, it is not possible to use the SessionID. The purpose of the website is to allow users to request certain types of insurance data. My website takes the request, formats it, forwards it to the appropriate insurance data source, then returns the data to the user. The request format is dictated by an ANSI standard. Part of the standard is that each request to a given data insurance source must have a unique identifier that is required to be in the format of an integer padded with leading zeros to a fixed length. So the only way to ensure a unique ID is for the server to read a counter from somewhere each time it receives and formats a request for forwarding to a data provider. The SessionID is not the correct format, and even if it were, a single user could submit multiple requests in a single session anyway.
-
No, it is not possible to use the SessionID. The purpose of the website is to allow users to request certain types of insurance data. My website takes the request, formats it, forwards it to the appropriate insurance data source, then returns the data to the user. The request format is dictated by an ANSI standard. Part of the standard is that each request to a given data insurance source must have a unique identifier that is required to be in the format of an integer padded with leading zeros to a fixed length. So the only way to ensure a unique ID is for the server to read a counter from somewhere each time it receives and formats a request for forwarding to a data provider. The SessionID is not the correct format, and even if it were, a single user could submit multiple requests in a single session anyway.
I see. What's the problem with InterlockedIncrement, then? It's thread safe, right? Unless you then store the value in a variable that is not thread safe, it should stay thread safe. If you need to store the value in a class property, you kan make it thread safe: [ThreadStatic] static int id; --- b { font-weight: normal; }
-
I see. What's the problem with InterlockedIncrement, then? It's thread safe, right? Unless you then store the value in a variable that is not thread safe, it should stay thread safe. If you need to store the value in a class property, you kan make it thread safe: [ThreadStatic] static int id; --- b { font-weight: normal; }
InterlockedIncrement is atomic and threadsafe. The function call is not. Example: int id; int GetNextIndex() { InterlockedIncrement(id); return id; } Suppose id value is currently 0. Thread 1 enters GetNextIndex, executes InterlockedIncrement, but then gets timesliced before the new id value is returned. The id value is now 1 but Thread 1 has been suspended before the value was returned. Thread 2 enters GetNextIndex, increments id once more, and exits successfully. The id value is now 2 and Thread 2 has an index value of 2. Thread 1 gets queued for execution again, re-enters GetNextIndex where it was interrupted, but the value has since been incremented to 2. Thread 1 now also has an index value of 2, and the results are corrupted because of the re-entrant effect. ThreadStatic will not work because that directs the compiler to give each thread it's own local copy of the variable, so each thread will increment a seperate counter in thread local storage which does not enforce a system wide unique value. Anyway, I did some preliminary experiments using a critical section on the entire function hosted in a Remoting server, and it looks like it works OK. I am just a little leery about using a Lock without knowing a lot more about how Remoting manages it's threads. But so far so good ... Thanks, Robert
-
InterlockedIncrement is atomic and threadsafe. The function call is not. Example: int id; int GetNextIndex() { InterlockedIncrement(id); return id; } Suppose id value is currently 0. Thread 1 enters GetNextIndex, executes InterlockedIncrement, but then gets timesliced before the new id value is returned. The id value is now 1 but Thread 1 has been suspended before the value was returned. Thread 2 enters GetNextIndex, increments id once more, and exits successfully. The id value is now 2 and Thread 2 has an index value of 2. Thread 1 gets queued for execution again, re-enters GetNextIndex where it was interrupted, but the value has since been incremented to 2. Thread 1 now also has an index value of 2, and the results are corrupted because of the re-entrant effect. ThreadStatic will not work because that directs the compiler to give each thread it's own local copy of the variable, so each thread will increment a seperate counter in thread local storage which does not enforce a system wide unique value. Anyway, I did some preliminary experiments using a critical section on the entire function hosted in a Remoting server, and it looks like it works OK. I am just a little leery about using a Lock without knowing a lot more about how Remoting manages it's threads. But so far so good ... Thanks, Robert
Why not use the return value from the method? Then it's thread safe:
int id; int GetNextIndex() { return InterlockedIncrement(id); }
I meant that you could use ThreadStatic to store the id after you created it:[ThreadStatic] int threadId; void CreateIndex() { threadId = GetNextIndex(); }
--- b { font-weight: normal; } -
Why not use the return value from the method? Then it's thread safe:
int id; int GetNextIndex() { return InterlockedIncrement(id); }
I meant that you could use ThreadStatic to store the id after you created it:[ThreadStatic] int threadId; void CreateIndex() { threadId = GetNextIndex(); }
--- b { font-weight: normal; }Yes, I believe that would probably work. Actually what would really happen is the compiler would implicitly create a temporary return value so the execution would look more like int GetNextIndex() { int _tempreturn _tempreturn = InterlockedIncrement(id) return _tempreturn } The actual return could possibly still occur on a different timeslice for a given thread, but presumably it would have already been pushed onto a stack that was restored so the value would still be correct. I think what I have will work though. Thanks, Robert
-
Yes, I believe that would probably work. Actually what would really happen is the compiler would implicitly create a temporary return value so the execution would look more like int GetNextIndex() { int _tempreturn _tempreturn = InterlockedIncrement(id) return _tempreturn } The actual return could possibly still occur on a different timeslice for a given thread, but presumably it would have already been pushed onto a stack that was restored so the value would still be correct. I think what I have will work though. Thanks, Robert
I don't know if the return value actually is passed on the stack or in a register, but either way that operation surely is thread safe, as both the stack and the register state is local to the thread. If another thread is executing the same code simultaneously, it will have it's own stack and registers. --- b { font-weight: normal; }