Send a reference to a variable instead of it's value - c#

I have a function that does a long task and I want to update a variable somewhere else occasionally with status updates. (If there is a better method for doing this, that's fine too) I'm writing a library and this code might be called several times at once so creating another variable in the same class that stores the variable isn't an option. Here is what my code might look like:
public static bool Count(int Progress, int CountToWhat) {
for (int i = 0; i < CountToWhat; i++) {
Progress = CountToWhat / i; // This is how I'd like to update the value, but obviously this is wrong
Console.WriteLine(i.ToString());
}
}

This is not a good way of providing updates to your callers.
Better you define one ore more events in your class library (like OnError, OnProgress, etc.).
You can raise, for example, OnProgress when you want to notify progress in a certain operation:
for (int i = 0; i < CountToWhat; i++) {
OnProgress(CountToWhat / i);
Console.WriteLine(i.ToString());
}
This is a much better way of doing it, especially when notifying from worker threads.

Change the signature to:
public static bool Count(ref int Progress, int CountToWhat)
And when you call it, use the ref keyword before the variable that you pass in as the first argument.

You can use
int Progress = 0;
public static bool Count(ref int Progress, int CountToWhat)
{
....
}
Or
int Progress; //without init
public static bool Count(out int Progress, int CountToWhat)
{
....
}

A better way might be to pass an Action<int> delegate to be called to report progress:
public static bool Count(int CountToWhat, Action<int> reportProgress)
{
for (int i = 0; i < CountToWhat; i++)
{
var progress = CountToWhat / i;
reportProgress(progress);
Console.WriteLine(i.ToString());
}
}
then you'd use it like:
Count(100, p => currentProgress = p);
You could also use the BackgroundWorker class to run your long running task, and utilize its ProgressChanged event.

Related

Locking and ref values from external function

I'm trying to track down a bug that I think might be related to the applications multithreading. I've simplified the code below:
class Outer {
private static int count;
//this function is called from multiple threads in quick succession
public void DoFoo() {
Inner.Increment(ref count);
}
}
class Inner {
private readonly static object mLock = new object();
public static string Increment(ref count) {
lock (mLock) (
if (count > 1000)
count = 0;
count++;
}
return count.ToString();
}
}
Can the locking guarantee the safety of a variable passed in that way? Is there any copying of count going on that seems non-obvious and may break the memory safety? I was thinking it might return a new int and do the assignment at the end of the method or something. Apart from that it's my understanding that the lock section would handle any caching issues.
The error which bought the issue to our attention was seemingly one of the threads having a stale version of count.
The problem here is that some other thread could read directly Outer.count when it is == 0, because you can access Outer.count without first having obtained a lock (normally as written in your code, count can be 0 only before the first call to Inner.Increment, from then on it can only have a value between 1 and 1001)
Lockless can be done in this way:
class Inner
{
public static string Increment(ref int count)
{
while (true)
{
int original = count;
int next = original;
if (next > 1000)
{
next = 0;
}
next++;
if (Interlocked.CompareExchange(ref count, next, original) == original)
{
return next.ToString();
}
}
}
}
I'm calculating a next value and using it (through Interlocked.CompareExchange) only if count hasn't changed in the meantime.

How do i stop the variable from resetting

In my code I have a method with the two parameters.
One parameter takes in an int value and the other an array.
e.g
public void NextSong(int i, TagLib.File[] queue)
{
i++;
SONG_URL = queue[i].Name;
Stop();
Play();
}
My problem here is every time this variable is called like so:
NextSong(0, SongQueue);
It reverts back to the amount placed in the parameter field. How do I stop this?
Two ways:
public int NextSong(int i, TagLib.File[] queue)
{
i++;
SONG_URL = queue[i].Name;
Stop();
Play();
return i;
}
int i = 0;
i= NextSong(i, SongQueue);
Here we are passing a variable of i to the method, during the method we increment that variable and then pass it back via the return. We now have reference to that variable.
OR
public void NextSong(TagLib.File[] queue, out int i)
{
i++;
SONG_URL = queue[i].Name;
Stop();
Play();
}
int i = 0;
NextSong(SongQueue, out i);
This uses the out functionality, which enforces someone to pass a variable that will be returned. It passes the variable by reference (You could also use ref, but since int can't be null, it doesn't change much in this case).
That is working as expected, as long as 0 it will keep on being passed, the variable will always reset.
What you can do it to change the signature of the NextSong method to yield back the value of i:
public int NextSong(int i, TagLib.File[] queue)
{
i++;
SONG_URL = queue[i].Name;
Stop();
Play();
return i;
}
Then in your code you initialize some global value to 0 and call the method as follows: globalVariable = NextSong(globalVariable, SongQueue).

Call BackgroundWorker from static method

it's the first question I ask so please be tolerant if I do something wrong.
I am writing a software to read data from a serial port a then use it to update the status of a static list of objects. Every data I receive is a communication of a wireless node and it represents its status. I solved the reading part and I am handling the search and update part.
I would like to use the background worker to search the element in the list and then update it, assuring the user a clean and smooth UI. The problem is that I read the bytes through a static function, and from that static function I should call the backgroundworker to perform the task. I read on the dotnetperls guide that "RunWorkerAsync can be called anywhere in your code.", but when I try to call it from the static function, Visual Studio doesn't let me do it.
Can anyone help me?
[edit: code added]
This is the extract of my static method:
public static void Add(Byte[] received)
{
List<byte[]> messages = new List<byte[]>();
int lastdollars = 0;
byte[] tempmess = new byte[20]; //The message is 20 digits
lock (BufferLock)
{
//I add the last bytes to the buffer (it's a list of bytes)
Buffer.AddRange(received);
if (Buffer.Count < TOTALMESSAGELENGTH) return;
String temp = Encoding.UTF8.GetString(Buffer.ToArray());
//I check the buffer to look for complete messages (there are tokens at the start and at the end
for (int i = 0; i <= (temp.Length - TOTALMESSAGELENGTH + 1); i++)
{
if ((temp.Length > i + TOTALMESSAGELENGTH) &&
(temp.Substring(i, TOKENLENGTH) == STARTTOKEN) &&
(temp.Substring((i + TOKENLENGTH + MESSAGELENGTH), TOKENLENGTH) == ENDTOKEN))
{
//if I find a message, I put it into the list of messages, I save its position and I continue to look for other messages
tempmess = Encoding.UTF8.GetBytes(temp.Substring(i, TOTALMESSAGELENGTH));
messages.Add(tempmess);
lastdollars = i;
i += TOTALMESSAGELENGTH - 1;
}
}
if (messages.Count == 0)
return;
//I delete the buffer that I'm using and I need to call the background worker
Buffer.RemoveRange(0, (lastdollars + TOTALMESSAGELENGTH));
}
worker.RunWorkerAsync(messages); //Error: An object is required for the non-static field, method, or property 'namespace.Form1.worker'
}
I tried both to define manually the backgroundworker with:
private readonly BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += worker_DoWork;
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
and adding it through the Toolbox, but the result is the same.
You cannot access instance variables in static methods. Hence the error. Try and make the BackgroundWorker instance static. Something like the following.
private readonly static BackgroundWorker worker = new BackgroundWorker();
Not very sure if this will not break any other of your code.
Hope this helps.
This doesn't really have anything to do with BackgroundWorker or any specific class. It is just how the C# language works.
You can't access non-static members from a static function. A static function has no implicit this parameter that makes it run against a particular instance of the class. You can run it without ever creating any instances of the class.
This worker
private readonly BackgroundWorker worker = new BackgroundWorker();
will be created once for each instance of the class. But you can call the Add function without having any instances.
For example, this doesn't work for the same reason:
class Adder
{
public int sum = 0;
public static void Add(int x)
{
sum += x; // can't reference "sum" from static method!
}
}
...
Adder.Add(5)
but this works:
class Adder
{
public int sum = 0;
public void Add(int x) // no longer static
{
sum += x; // this refers to the "sum" variable of this particular instance of Adder
}
}
...
var adder = new Adder();
adder.Add(5);
and this also works (but differently!):
class Adder
{
public static int sum = 0; // we made sum static (there is exactly one, instead of a separate sum for each instance)
public static void Add(int x)
{
sum += x; // this refers to the static sum variable
}
}
...
Adder.Add(5);

Updating progress bar from a threadpool c#

I have trying to process some data using multithreading where I am using threadpool to generate threads equal to the number of cores(Limited to .NET 2.0 to 3.5 so cant use TPL).
All my threads execute the same function operating in different parts of my data.
My problem is I am unable to update the progress bar from the threads of the threadpool. Found solutions such as invoke and Background worker but could not really understand how to use them please help me out how to use them.
my code looks like
private static float[] inpdat=new float[1000];//The input array to process
//The spawned threads
public void dowork(object o)
{
int np = (int)o;
for(int i=np;i<inpdat.length;i=i+Environment.ProcessorCount)
{
//do some processing
if(np==0)
{
//update progress bar here
}
}
}
//The main thread
for (int npou = 0; npou < numproc; npou++)
{
resetEvents[npou] = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem(new WaitCallback(dowork), npou);
PetrelLogger.InfoOutputWindow("manual reset event set");
}
Speed is of paramount importance to me so would be very helpful if the cross thread calling takes up minimum time.
Thanks
Here is an example:
ThreadPool.QueueUserWorkItem(new WaitCallback(o =>
{
// worker method implementation
.....
progressBar1.Invoke(new MethodInvoker(() => progressBar1.Value = 20));
}));
There is a little you can do with updating user controls, in your case Progress bar.
Add your form as the input parameter, or add some callback interface for the results, that your form will implement:
interface IMyCallback
{
void Progress(int progress);
}
In form implementation add following code:
void Progress(int Progress)
{
if(this.InvokeRequired)
{
this.BeginInvoke(new ParametrizedThreadStart(Inv_Progress), Progress);
}
else
{
Inv_Progress(Progress);
}
}
void Inv_Progress(object obj)
{
int progress = obj as int;
// do your update progress bar work here
}
Now you can do following:
public void dowork(object o)
{
int np = (int)o;
for(int i=np;i<inpdat.length;i=i+Environment.ProcessorCount)
{
//do some processing
if(np==0)
{
myCallback.Progress(0);
}
}
}
A standard invoke is probably easiest, and you can use an anonymous delegate to make it cleaner.
int n = 5;
myProgressBar.Invoke(
delegate
{
myProgressBar.Value = n;
}
);
Keep in mind that in certain scenarios (e.g. looped use of this delegate from within one thread) you may need to declare a delegate and pass the value into it as a parameter. If you don't, you can get strange behaviour with locals. This is the case for use of anonymous methods and the Action class, too.

Cancel ThreadPool .QueueUserWorkItem Task

I need to cancel a background task started using ThreadPool.QueueUserWorkItem(...). I know a BackgroundWorker has constructs especially for this sort of thing, but I believe it's overkill in this case, since no user interface is involved. By cancellation, I simply mean force the completion of the callback method.
What are the pitfalls of adding something like the following to my class?
// Cancellation Property.
private bool _canceled;
public bool CancelTask
{
get { return _canceled; }
set { _canceled = value; }
}
public void DoSomeTask()
{
int iterations = 50;
ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadPoolCallback), iterations);
}
private void ThreadPoolCallback(object state)
{
if (_canceled)
return; // don't even start.
int iterations = (int)state;
for (int i = 0; !_canceled && i < iterations; i++)
{
//
// do work ...
//
// This allows you to cancel in the middle of an iteration...
if (_canceled)
break;
}
}
Is there a better way?
I'd use a method CancelTask() rather than a property. The point is that callers should be able to cancel a task, but no one should be able to un-cancel a task.
Then you need to be sure that the read and the write of _cancelled have the appropriate memory barriers otherwise one thread might not ever observe the change made by the other thread. For this I'd use Thread.VolatileWrite (inside CancelTask) and Thread.VolatileRead (inside your loop)

Categories