|
I put another variable in my lockless queue to measure the retry count (the number of times it has to spin again because something changed), and in my test bench, it seems that an additional 50% of operations are done, so 100 enqueues ends up being something like 100 successful operations and 50 respins, approximately. I'm not sure how well my numbers compare with other implementations, but that does seem like a lot. It seems from the result that the lockless implementation works best with little contention, but I'm curious to know the theory behind it.
|
|
|
|
|
Cyrilix wrote: measure the retry count (the number of times it has to spin again because something changed)
Not sure I understand what you mean. Care to share some code here?
Cyrilix wrote: I'm curious to know the theory behind it.
You could use reflector to investigate how it has been implemented in .NET although I expect you would also need to study the IL specification and still will be kept in the dark on how the native code looks (it is very likely they use special assembly instructions in the end).
|
|
|
|
|
My internet was down for a little so I couldn't post right away.
public void Enqueue(T data)
{
LockFreeQueueNode<T> tempTail = null;
LockFreeQueueNode<T> tempTailNext = null;
LockFreeQueueNode<T> newNode = new LockFreeQueueNode<T>(data);
newNode.Data = data;
do
{
tempTail = tail;
tempTailNext = tempTail.NextNode;
if (tempTail == tail)
{
if (tempTailNext == null)
{
if (Interlocked.CompareExchange(ref tempTail.NextNode, newNode, tempTailNext) == tempTailNext)
break;
}
else
{
Interlocked.CompareExchange(ref tail, tempTailNext, tempTail);
}
}
Interlocked.Increment(ref retryCount);
} while (true);
Interlocked.CompareExchange(ref tail, newNode, tempTail);
Interlocked.Increment(ref count);
}
I believe this code was actually taken somewhere from a Codeproject article (but I happened to find it online from a different source). The part that's in bold is the important line that I added to measure the retry count, basically everytime we are unable to break out of the while loop and need to retry the operation again.
|
|
|
|
|
Hi,
OK, if retryCount goes up it tells me nothing much is happening outside your queue; you and I agree on
"lockless implementation works best with little contention" and to reduce contention a lot of things should be going on outside the queue.
|
|
|
|
|
Contention is always bad, but generally lockless code should be faster under contention than using locks.
With lockless code, when multiple threads use CompareExchange concurrently, at least one will succeed. So you're not wasting any time compared to the locked version.
Did you include the Interlocked.Increment(ref retryCount) when timing?
Like locks, interlocked operations aren't cheap, so you should avoid doing too many of them. Do you really need "count"?
Currently you're doing at least 3 interlocked operations per insertion - maybe a lock really is faster in this case.
And what hardware did you test it on? How many cores? Are you using hyper-threading?
You might be better off by slowing down the retry operation - on hyper-threaded processors, retrying too often slows down the other thread running on that processor. And in general, all threads constantly accessing memory isn't a good idea. Try adding a small Thread.SpinWait when retrying.
|
|
|
|
|
Yes, I include everything when timing. I also saw that count could be eliminated to no negative effect on the algorithm itself. I just wouldn't have anything to keep track of approximately what the count is, which is OK.
The hardware that I'm running it on is an Athlon64 X2 4400+ (2.2 GHz) with 2 cores and no hyper-threading. One thing I did was instead of slowing down the retry, I slowed down the enqueue/dequeue rate, by adding some other intensive math in between. This reduces the contention rate significantly. Before, I'd have about 50% extra operations... slowing it down to a reasonable level drops the amount of additional operations down to 4-6%. Under such a case, the lockless algorithm is equal or better to the lock algorithm.
One question though, what do you mean to imply when you say "With lockless code, when multiple threads us CompareExchange concurrently, at least one will succeed." Isn't it the same with locks? When multiple threads try to enter a critical section, at least one, and only one will succeed. The others will wait their turn.
|
|
|
|
|
Its not so much the fact that its lockless but the implementation is slow.. Each enqueue and dequeue here require adding a new class ( which is the node) , a new is VERY expensive and uses a lock around the GC allocator. So you have removed the lock around enqueue and dequeue but hit the worse GC lock. A per formant lock less queue would pre-create and re-use its nodes OR manage its own memory with structs and unsafe. An array based queue would not require new nodes and only needed to new when growing the array and hence would offer much better base performance but is harder to make lock less.
secondly you are making it worse with a second interlock. Interlocks are not cheap they cause the pipeline to stall and lock they are cheaper than a full lock , note however most full locks just use an interlock on a variable and block if it is in use , since an enqueue without a new is FAST the lock will not really be active long and the other lock implementations ends up just being an interlock compare.
Now adding to a queue is probably a very cheap operation maybe 10 cycles so probably no contention with only 5 threads if they do normal work. ( In a bench mark it generate contention but this is not a real scenario a program would spend very little time doing the enqueue and dequeue.
Ben
|
|
|
|
|
I see what you mean. The second interlocked operation was removed (because it was more or less useless for a real data structure), but the implementation could be better. Thanks for the tip.
|
|
|
|
|
dear friends
how to convert a header file in c language into its c# equalent
this is my code.... help me out guys just give me ideas
void nrerror(char error_text[]);
int *ivector(int nl, int nh);
double *dvector(int nl,int nh);
char *cvector(int nl, int nh);
int **imatrix(int nrl,int nrh,int ncl,int nch);
double **dmatrix(int nrl,int nrh,int ncl,int nch);
void print_iMatrix(FILE *fp, int **imatrix, int rows, int cols);
void print_dMatrix(FILE *fp, double **dmatrix, int rows, int cols);
void free_dvector(double*v,int nl,int nh);
void free_cvector(char * c,int nl,int nh);
void free_ivector(int * v,int nl,int nh);
void free_imatrix(int **m ,int nrl,int nrh,int ncl,int nch);
void free_dmatrix(double ** m,int nrl,int nrh,int ncl,int nch);
|
|
|
|
|
lawrenceinba wrote: int *ivector(int nl, int nh);
if you don't want to use unsafe code, just use int . int ivector(int nl, int nh); will be the equivalent. But in C#, this function will return the value not the pointer.
lawrenceinba wrote: int **imatrix(int nrl,int nrh,int ncl,int nch);
Same like the above. You can use ref or out with the parameters and assign value to there. Let your method return void. It is same pattern like int.TryParse(string,out int)
In C#, all primitive types are passed by value. To make it pass by reference, you have to use ref or out with it. So all pointer variables (int*,double*) should be marked with ref or out to pass as reference.
|
|
|
|
|
C# doesn't use header files.
What is it that you are trying to do? Convert a C program to C# without any knowledge of C#?
Despite everything, the person most likely to be fooling you next is yourself.
|
|
|
|
|
ya i know but.... im asking to create a dll file.. for library
ya im a beginner in c#
going on studing stuff abt c#.... s i have to convert a c++ code to c#
|
|
|
|
|
lawrenceinba wrote: going on studing stuff abt c#.... s i have to convert a c++ code to c#
I'd suggest to try something simple as you are a beginner.
|
|
|
|
|
ya ill go step by step only.. but i have to complete it in three months... so hopefully ill finish it if members here clears my doubts
|
|
|
|
|
It is quite a chanllenge job for a beginner. If you really want to do this, I am afraid you need a third-party tool, however, I could not remember the name very well. Maybe you can turn to managed C++.
Tan Li
I Love KongFu~
|
|
|
|
|
dear friend
im a beginner only in c#
got enough knowledge in c & c++
so i'll do it
i need help only in c#
|
|
|
|
|
Well, I did not mean unmanaged C++, which is different form C++ in .net world. Just for you information.
Tan Li
I Love KongFu~
|
|
|
|
|
Ah C++, it seems so archaic these days. The snippet you provide is presumably a set of methods in a class. Where is the data these methods operate on? Presumably you've got to translate the arrays or chunk of memory to C# as well?
In which case, a character array is best represented as a string .
Am I right in thinking that ivector() creates a vector and free_ivector releases it? Same with imatrix?
Presumably you know that header files (thank the maker) do no exist in C#...?
Regards,
Rob Philpott.
|
|
|
|
|
Hi,
not sure what it is you need.
if you want to create a classic DLL, callable by unmanaged code, then I would not do that in a CLR language...
if you want to create a class with some functionality and methods, forget the header file, and create the class from scratch; you can build a DLL from it, it will be callable in .NET by any managed language (C#, VB.NET, C++/CLI, ...) but not (or not easily) by unmanaged code (C, C++, ...).
if you want to keep existing native code and provide a managed wrapper for it, so it can more easily be used by an app in a managed language, then you would need P/Invoke (google it, and visit www.pinvoke.net), and use accurate prototypes; if so, all pointers should be implemented through the IntPtr type.
|
|
|
|
|
i'll update my needs wit u in mail
thanks for the website friend
|
|
|
|
|
I am searching for a fast string to integer conversion algorithm. Int32.Parse is too slow for my purposes. I implemented an algorithm that was faster by orders of magnitude, but I was hoping someone could point me to an existing library that includes such functions, or at least to a paper to make sure I'm working correctly.
Thank you.
|
|
|
|
|
HosamAly wrote: Int32.Parse is too slow for my purposes
Interesting! Can you give more information about your application type where minor things like this is affected?
|
|
|
|
|
I am parsing a live feed that contains many numbers. The feed comes from a trusted source (i.e. format is guaranteed to be correct), and the numbers are simple ASCII integers (no localization, no thousands separator, etc). Int32.Parse is simply too slow for such "simple" operations. In my benchmarks, it's taking 5-16 times more than some of my implementations.
|
|
|
|
|
So you say you've written a fast implementation of int parsing, that performs better than int.Parse - so what exactly are you asking? If you've done it right? You've not posted your code if so!
|
|
|
|
|
I am asking whether there exists a library that includes such functions, in hope that it would be better tested and optimized than my own implementation. If there isn't, I was hoping to get some links to papers or algorithms for how to convert a string to a number efficiently.
|
|
|
|
|