While using a global integer named GlobalID
that I use as a counter,
the following code works fine:
MyFunction(myClass thisClass, Int ID)
{
ListOfMyClass.add(thisClass)
If (thisClass.IsPropertyValueAboveZero)
{
ID = GlobalID;
}
GlobalID++;
Foreach (class someClass in ListOfClasses)
{
MyClass newClass = new MyClass(GlobalID, ID)
MyFunction(newClass, ID) //Recursive Call
}
}
I'm basically using GlobalID
as a incrementing counter for each time the function is called. The counter is assigned a starting position for the first time it executes. I'm using a global variable because I wanted to make sure the ID is accurately increased for each pass regardless of execution entering or leaving the recursive call. This function is called (the first time....) from a ForEach loop that assigns the start position of global variable
My goal is to use a Parallel.ForEach for the initial call instead of the regular For Each loop. My problem deals with the counter. I don't know how to manage that counter within multiple threads. If I pass it as a variable to the function, I believe I will have a inaccurate lower / used number leaving the recursive loop. The global variable ensures the next number is higher than the previous number. The thisClass.IsPropertyValueAboveZero
is just a arbitrary means of describing action based on a conditional statement. It has no meaningful reference to the rest of the code.
If I have multiple threads that have different starting positions for their counter, how do I accomplish making this thread safe? The only way I see at the moment is manually writing multiple versions of the same function and counter and using TaskFactory
For thread-safe counting, use the Interlocked methods: System.Threading.Interlocked.Increment(ref globalID)
private static int globalID;
// Be very careful about using a property to expose the counter
// do not *use* this value directly, but can be useful for debugging
// instead use the return values from Increment, Decrement, etc.
public int UnsafeGlobalID { get { return globalID; } }
Note: you need to use a field for the ref
. It is possible to expose the field through a property, but can be problematic in code. It is better to use Interlock methods such as Interlocked.CompareExchange
or explicit lock
statements around logic requiring the value in a synchronized manner. The return value for Increment
, Decrement
, and so on is usually what should be used inside logic.
My problem deals with the counter. I don't know how to manage that counter within multiple threads. If I pass it as a variable to the function, I believe I will have a inaccurate lower / used number leaving the recursive loop. The global variable ensures the next number is higher than the previous number.
If I have multiple threads that have different starting positions for their counter, how do I accomplish making this thread safe? The only way I see at the moment is manually writing multiple versions of the same function and counter and using
TaskFactory
The recursive call to MyFunction(newClass, ID)
will have the value of ID
, but I'm not sure what If (thisClass.IsPropertyValueAboveZero)
is supposed to do though. Is it to make sure you have a non-zero starting point? If so, it would be better to make sure it is non-zero before the initial call outside of this function.
Also the logic in the foreach loop doesn't make sense to me. In MyClass newClass = new MyClass(GlobalID, ID)
the ID
will be argument value, or if IsPropertyValueAboveZero
is true it will be the current value of GlobalID
. So ID
will typically be less than GlobalID
since GlobalID
is incremented before the foreach
loop. I think you are passing GlobalID
when you do not need to.
// if IsPropertyValueAboveZero is intended to start above zero
// then you can just initialize the counter to 1
private static int globalID = 1;
public void MyFunction(myClass thisClass, int id)
{
// ListOfMyClass and ListOfClasses are probably not thread-safe
// and you may need to add locks around the Add and get a copy
// of ListOfClasses before the foreach enumeration
// You may want to look at https://stackoverflow.com/a/6601832/29762
ListOfMyClass.Add(thisClass);
foreach (class someClass in ListOfClasses)
{
int newId = System.Threading.Interlocked.Increment(ref globalID);
MyClass newClass = new MyClass(newId);
MyFunction(newClass, newId); //Recursive Call
}
}