Task Management and Usage? - c#

So I got a server that shoots off the below task in a while loop it's functioning as my client listener. The issue seems like it wants to loop as fast as possible through the clients which is great! But it fires tasks off too fast before the previous task is done a new one happens ( for the same client).
I don't want it to wait for the task to complete! I want it to shoot more tasks but just not create anymore tasks for a specific client that already has an existing task.
What is the best way to go about this... I see a lot of people using WhenAll or something but I don't care about All the tasks.
//the below is in a while loop which goes through the clients that are connected.
if (stream.DataAvailable)
{
// the below task is the one that is firing before the pervious fired one completes.
Task DataInterpetTask = Task.Factory.StartNew(() =>
{
int totalBuffer, totalRecieved = 0;
byte[] totalBufferByte = new byte[4];
byte[] buffer = new byte[0];
byte[] tbuffer;
int rLength, prevLength;
stream.Read(totalBufferByte, 0, 4);
totalBuffer = BitConverter.ToInt32(totalBufferByte, 0);
Console.WriteLine("got stuff: " + totalBuffer);
byte[] buf = new byte[c.getClientSocket().ReceiveBufferSize];
while (totalBuffer > totalRecieved)
{
rLength = stream.Read(buf, 0, buf.Length);
totalRecieved = rLength + totalRecieved;
if (rLength < buf.Length)
{
byte[] temp = new byte[rLength];
Array.Copy(buf, temp, rLength);
buf = temp;
}
prevLength = buffer.Length;
tbuffer = buffer;
buffer = new byte[buffer.Length + rLength];
Array.Copy(tbuffer, buffer, tbuffer.Length);
buf.CopyTo(buffer, prevLength);
}
String msg = Encoding.ASCII.GetString(buffer);
if (msg.Contains("PNG") || msg.Contains("RBG") || msg.Contains("HDR"))
{
Console.WriteLine("Receiving Picture");
RowContainer tempContainer;
if ((tempContainer = MainWindow.mainWindow.RowExists(c)) != null)
{
tempContainer.Image = buffer;
Console.WriteLine("Updating row: " + tempContainer.rowNumber);
MainWindow.mainWindowDispacter.BeginInvoke(new Action(() =>
MainWindow.mainWindow.UpdateRowContainer(tempContainer, 0)));
}
else
{
Console.WriteLine("Adding row for Picture");
MainWindow.mainWindowDispacter.BeginInvoke(new Action(() =>
MainWindow.mainWindow.CreateClientRowContainer(c, buffer)));
}
return;
}
String switchString = msg.Substring(0, 4);
if (msg.Length > 4)
msg = msg.Substring(4);
MainWindow.mainWindowDispacter.BeginInvoke(new Action(() =>
{
if (MainWindow.debugWindow != null)
MainWindow.debugWindow.LogTextBox.AppendText("Received message " + msg + " from client: " + c.getClientIp() + " as a " + switchString + " type" + Environment.NewLine);
}));
RowContainer tContain = MainWindow.mainWindow.RowExists(c);
if(tContain == null)
return;
switch (switchString)
{
case "pong":
c.RespondedPong();
break;
case "stat":
tContain.SetState(msg);
MainWindow.mainWindow.UpdateRowContainer(tContain, 1);
break;
case "osif":
tContain.Os = msg;
MainWindow.mainWindowDispacter.BeginInvoke(new Action(() =>
MainWindow.mainWindow.UpdateRowContainer(tContain, 2)));
break;
case "idle":
tContain.idle = msg;
MainWindow.mainWindowDispacter.BeginInvoke(new Action(() =>
MainWindow.mainWindow.UpdateRowContainer(tContain, 3)));
break;
}
});
}

If you don't want to start a new operation for a given client until the previous one has completed, then just keep track of that. Either move the client object to some "in progress" list, so that it's not even in the list of clients that you are processing in your loop, or add a flag to the client object class that indicates that the operation is "in progress", so that your loop can ignore the client until the current operation has completed (e.g. if (c.OperationInProgress) continue;).
That said, it appears that you are using polling (i.e. checking DataAvailable) to manage your I/O. This is a really inefficient approach, and on top of that is the root cause of your current problem. If you were using the much better asynchronous model, your code would be more efficient and you wouldn't even have this problem, because the asynchronous API would provide all of the state management you need in order to avoid overlapping operations for a given client.
Unfortunately, your code example is very sparse, missing all of the detail that would be required to offer specific advice on how to change the implementation to use the asynchronous model (and what little code there is, includes a lot of extra code that would not be found in a good code example). So hopefully the above is enough to get you on track to the right solution.

Related

Response cut while reading System.Net.Sockets

I have this code inside of a controller that is called from a view by multiple users. The purpose is to read data from a socket while the socket has information to deliver. Multiple calls can happen simultaneously. The problem is, for a same call the Socket will sometimes cut the message. We will not read it entirely. Is there something wrong in my call that could lead to an incomplete reading of the Socket ? I am not able to reproduce it on my dev environment I just know that on the production we have responses from the Socket being randomly cut / incomplete.
int byteCount = 1;
string response = "";
int total = 0;
bytesReceived = new Byte[8000];
bool bytesAreAvailable = true;
while (byteCount > 0 || bytesAreAvailable)
{
try {
byteCount = m_oSocket.Receive(bytesReceived, bytesReceived.Length, 0);
total += byteCount;
Debug.WriteLine("Bytecount: " + byteCount.ToString());
Debug.WriteLine("Avalable: " + m_oSocket.Available.ToString());
if (m_oSocket.Available > 0)
bytesAreAvailable = true;
else
bytesAreAvailable = false; //Everything was read
response += Encoding.UTF8.GetString(bytesReceived, 0, byteCount);
}
catch(Exception e)
{
Debug.WriteLine(e.Message);
}
}
Debug.WriteLine(response.ToString());
Thanks a lot for any help / tips you could have on solving my issue

C# Multithreading duplicated

I'm trying to make a tool that get source string from many URL I provided. And I use this code for multithreading
new Thread(() =>
{
while (stop != true)
{
if (nowworker >= threads)
{
Thread.Sleep(50);
}
else
{
if (i <= urllist.Count - 1)
{
var thread = new Thread(() =>
{
string source = GetSource(urllist[i]);
SaveToFile(source, i + ".txt");
});
thread.Start();
i++;
nowworker += 1;
}
else
{
stop = true;
}
}
}
}).Start();
It's run very smooth until I check the result and have some duplicated result and missing some url I provided if using less thread for many url(10 thread - 20 url) but there's no problem when using 20 thread for 20 url.
Please help me. Thank you.
if (i <= urllist.Count - 1)
{
var thread = new Thread(() =>
{
string source = GetSource(urllist[i]);
SaveToFile(source, i + ".txt");
});
thread.Start();
i++;
nowworker += 1;
}
The method you're passing to the thread is not guaranteed to execute before i is updated (the i++). Infact, it's very unlikely that it will. This means that multiple threads may use the same value of i, and some values of i will not have any threads executing it.
Even worse, GetSource may use a different value of i than SaveToFile.
Have a readup here: http://jonskeet.uk/csharp/csharp2/delegates.html
This will fix it:
if (i <= urllist.Count - 1)
{
var currentIndex = i;
var thread = new Thread(() =>
{
string source = GetSource(urllist[currentIndex]);
SaveToFile(source, currentIndex + ".txt");
});
thread.Start();
i++;
nowworker += 1;
}
Even better, you can replace the entire block of code with this:
Parallel.For(0, urlList.Count - 1,
new ParallelOptions { MaxDegreeOfParallelism = threads },
i =>
{
string source = GetSource(urllist[i]);
SaveToFile(source, i + ".txt");
}
);
Which will get rid of the code-smelly Thread.Sleep() and let .NET manage spinning up threads for you

Serializing tasks using a Memory Mapped File

I have a bunch of incoming web requests which I need to serialize and process one after each other. I cannot process more than one at a time. My current solution is to run a tool which can be accessed by a Web API using a Memory Mapped File acting as shared memory. I also need a Mutex to allow exclusive access to the shared memory. An event will be used to signal that a task was added.
So, basically we have there a multiple producers and one consumer. What follows is my first solution. Could someone tell whether or not there are some sort of race conditions or any other problems:
MemoryMappedFile MMF = MemoryMappedFile.CreateNew("Task_Queue", 5000);
MemoryMappedViewAccessor MMF_Accessor = MMF.CreateViewAccessor();
bool Mutex_Created = false;
Mutex Mutex = new System.Threading.Mutex(false, "Mutex", out Mutex_Created);
if(Mutex_Created==false)
{
// bad error
return;
}
EventWaitHandle EWH = new EventWaitHandle(false, EventResetMode.ManualReset);
Random Rand = new Random();
// Consumer
// work on the Tasks
Task.Factory.StartNew(() =>
{
while (true)
{
// wait until a task has been added
EWH.WaitOne();
// get exclusive access to read in task
Mutex.WaitOne();
byte[] Buffer = ASCIIEncoding.ASCII.GetBytes(new string(' ', 5000));
MMF_Accessor.ReadArray(0, Buffer, 0, Buffer.Length);
int Position = 0;
foreach (var b in Buffer) { if (b == 0) break; Position++; }
string Message = string.Empty;
for (int i = 0; i < Position; ++i)
{
Message += (char)Buffer[i];
}
if(string.IsNullOrEmpty(Message) == false)
{
Console.WriteLine(Message);
}
Mutex.ReleaseMutex();
EWH.Reset();
}
});
// Producer
// via a web request
Task.Factory.StartNew(() =>
{
while (true)
{
if(EWH.WaitOne(0))
{
// consumer must take in the task first
// wait a bit and then try again
Thread.Sleep(100);
break;
}
// wait until we access Shared Memory and claim it when we can
Mutex.WaitOne();
string Request = "Task 1 ";
byte[] Buffer = ASCIIEncoding.ASCII.GetBytes(Request);
Buffer[Buffer.Length - 1] = 0;
MMF_Accessor.WriteArray(0, Buffer, 0, Buffer.Length);
// Signal that a tasks has been added to shared memory
EWH.Set();
// release the mutex so that others can use the shared memory
Mutex.ReleaseMutex();
Thread.Sleep(Rand.Next(10, 1000));
}
});
// Producer
// via a web request
Task.Factory.StartNew(() =>
{
while (true)
{
// wait until we access Shared Memory and claim it when we can
Mutex.WaitOne();
string Request = "Task 2 ";
byte[] Buffer = ASCIIEncoding.ASCII.GetBytes(Request);
Buffer[Buffer.Length - 1] = 0;
MMF_Accessor.WriteArray(0, Buffer, 0, Buffer.Length);
// Signal that a tasks has been added to shared memory
EWH.Set();
// release the mutex so that others can use the shared memory
Mutex.ReleaseMutex();
Random r = new Random();
Thread.Sleep(Rand.Next(10, 1000));
}
});
while (Console.Read() != 'q') ;
Please note the posted code is just for demonstration purposes.

How to make run real time and faster refresh method with timer

I have script for refresh network with object label and panel but in script using looping mode with 'for'. I want to this real time refresh for 1 sec or 5 sec but because using 'for' make this procces need more time and get stuck screen. how to make the solution more quickly and in real time?
Thanks
public PosPing()
{
InitializeComponent();
RefreshPOS.Tick += new EventHandler(CheckPOSUG);
RefreshPOS.Start();
}
private void CheckPOSUG(object sender, EventArgs e)
{
Panel[] panelUG = new Panel[]{pnlPOSUG1,pnlPOSUG2,pnlPOSUG3,pnlPOSUG4,pnlPOSUG5,pnlPOSUG6,pnlPOSUG7,pnlPOSUG8};
Label[] LabelUG = new Label[]{lblUG1,lblUG2,lblUG3,lblUG4,lblUG5,lblUG6,lblUG7,lblUG8};
Label[] lblSpdUG = new Label[] { lblSpdUG1, lblSpdUG2, lblSpdUG3, lblSpdUG4, lblSpdUG5, lblSpdUG6, lblSpdUG7, lblSpdUG8 };
for (int x = 0; x < 8;x++ )
{
string IP = "192.168.135.1" + (x + 1).ToString();
var ping = new Ping();
var reply = ping.Send(IP, 10 * 1000);
LabelUG[x].Text = "POSBMS10" + x.ToString();
if (reply.Status == IPStatus.Success)
{
lblSpdUG[x].Text = reply.RoundtripTime.ToString() + " " + "ms";
panelUG[x].BackColor = Color.FromName("Lime");
}
else
{
lblSpdUG[x].Text = "Nonaktif";
panelUG[x].BackColor = Color.FromName("ButtonHighlight");
}
}
}
Without a good, minimal, complete code example, it's hard to know for sure how to best answer your question. But it looks like you are trying to ping eight different servers, which are represented by eight set of controls in your form.
If that is correct, then I agree with commenter Hans Passant that you should be using the SendPingAsync() method instead. This will allow you to execute the pings asynchronously, without blocking the UI thread, so that your program can remain responsive.
Because you are dealing with eight different servers, it makes sense to me that you should execute the eight pings asynchronously. To accomplish this, I would refactor the code a bit, putting the server-specific loop body into a separate method, so that each instance can be run concurrently.
Implementing it that way would look something like this:
private async void CheckPOSUG(object sender, EventArgs e)
{
Panel[] panelUG = new Panel[]{pnlPOSUG1,pnlPOSUG2,pnlPOSUG3,pnlPOSUG4,pnlPOSUG5,pnlPOSUG6,pnlPOSUG7,pnlPOSUG8};
Label[] LabelUG = new Label[]{lblUG1,lblUG2,lblUG3,lblUG4,lblUG5,lblUG6,lblUG7,lblUG8};
Label[] lblSpdUG = new Label[] { lblSpdUG1, lblSpdUG2, lblSpdUG3, lblSpdUG4, lblSpdUG5, lblSpdUG6, lblSpdUG7, lblSpdUG8 };
Task[] tasks = new Task[8];
for (int x = 0; x < 8; x++)
{
tasks[x] = PingServer(x, panelUG[x], LabelUG[x], lblSpdUG[x]);
}
try
{
await Task.WhenAll(tasks);
}
catch (Exception e)
{
// handle as appropriate, e.g. log and exit program,
// report expected, non-fatal exceptions, etc.
}
}
async Task PingServer(int index, Panel panel, Label ugLabel, Label spdLabel)
{
// NOTE: String concatenation will automatically convert
// non-string operands by calling calling ToString()
string IP = "192.168.135.1" + (index + 1);
var ping = new Ping();
var reply = await ping.SendPingAsync(IP, 10 * 1000);
ugLabel.Text = "POSBMS10" + x;
if (reply.Status == IPStatus.Success)
{
spdLabel.Text = reply.RoundtripTime + " ms";
// The Color struct already has named properties for known colors,
// so no need to pass a string to look Lime up.
panel.BackColor = Color.Lime;
}
else
{
spdLabel.Text = "Nonaktif";
panel.BackColor = Color.FromName("ButtonHighlight");
}
}

Why array behaves different when different thread access it

I need to parse large text that is similar to XML. Because the text it is not in memory ( I have a StreamReader object) placing that stream on memory is where I take the most time. So on one thread I place that stream into an array (memory). And I have another thread that process that array. But I am having wierd behavieours. For example take a look at this image:
Note that listToProcess[counter] = buffer and right now that should be listToProcess[10] = buffer Note that the debugger says that listToProcess[10]=null why!? . the other thread just reads the items it does not modify them. At first I thought that maybe the other thread was making that item = null but that is not the case. why am I experiencing this behavior?
In case you want to see my code here it is:
Semaphore sem = new Semaphore(0, 1000000);
bool w;
bool done = false;
// this task is responsible for parsing text created by main thread. Main thread
// reads text from the stream and places chunks in listToProces[]
var task1 = Task.Factory.StartNew(() =>
{
sem.WaitOne(); // wait so there are items on list (listToProcess) to work with
// counter to identify which chunk of char[] in listToProcess we are ading to the dictionary
int indexOnList = 0;
while (true)
{
if (listToProcess[indexOnList] == null)
{
if (done)
break;
w = true;
sem.WaitOne();
w = false;
if (done)
break;
if (listToProcess[indexOnList] == null)
{
throw new NotFiniteNumberException();
}
}
// add chunk to dictionary
ProcessChunk(listToProcess[indexOnList]);
indexOnList++;
}
}); // close task1
bool releaseSem = false;
// this main thread is responsible for placing the streamreader into chunks of char[] so that
// task1 can start processing those chunks
int counter = 0;
while (true)
{
char[] buffer = new char[2048];
// unparsedDebugInfo is a streamReader object
var charsRead = unparsedDebugInfo.Read(buffer, 0, buffer.Length);
if (charsRead < 1)
{
listToProcess[counter] = pattern;
break;
}
listToProcess[counter] = buffer;
counter++;
if (releaseSem)
{
sem.Release();
releaseSem = false;
}
if (counter == 10 || w)
{
releaseSem = true;
}
}
done = true;
sem.Release();
task1.Wait();
Edit
Sorry in other words why do I hit this break point:
I thought that counter was the problem but maybe I am doing something wrong with the semaphore...
You have a counter++ so the one you updated before that was at index 9, not index 10.
Meaning : your claim that it set
listToProcess[10] = buffer:
Is incorrect: it set
listToProcess[9] = buffer:

Categories