I have a task that is saving my DataTable in to a file every 10 seconds:
void WriteTask(DataTable dt, bool final)
{
if (final)
{
exiting = false;
}
while (!exiting)
{
lock (users)
{
try
{
dt.WriteXml(filePath+ "users.xml_be");
File.Copy(#$"{filePath}users.xml_be", #$"{filePath}users.xml_betemp");
File.Replace(#$"{filePath}users.xml_betemp", #$"{filePath}users.xml", #$"{filePath}users.xml_be2");
if (final)
exiting = true;
}
catch (Exception ex)
{
try
{
File.AppendAllText($"{filePath}log.txt", $"{DateTime.Now.ToString()} {ex.Message}" + Environment.NewLine);
File.AppendAllText($"{filePath}log.txt", $"{ex.StackTrace}" + Environment.NewLine);
File.AppendAllText($"{filePath}log.txt", "////////////////////////////////////////////////////////////////" + Environment.NewLine);
}
catch (Exception)
{
client.SendMessage(tChannel, ErrorMes1);
client.SendMessage(tChannel, $"{ex.Message}|{ex.StackTrace}");
}
}
}
Thread.Sleep(10000);
}
}
And recently I noticed that file are not getting changed. Weirdiest think is that when i open file in notepad++, its saying that the file has been chaged and it wants to reload it, but afte I reload the fle there is not chnages inside. Could it be because file is getting pretty big? It have around 1mil of lines.
Update:
So, I created async tasks for all things that have to do with datatables:
Task that is in a unending loop, saving every 30 seconds
async void WriteTask(DataTable dt, bool final)
{
if (final)
{
exiting = false;
}
while (!exiting)
{
Task UvalClockTaksTask = new Task(() => UvalClockTaksAsync());
Task dbSavingTask = new Task(() => WriteTaskAsync(dt, final));
Console.WriteLine("start saving");
UvalClockTaksTask.Start();
await UvalClockTaksTask;
dbSavingTask.Start();
await dbSavingTask;
Console.WriteLine("saved");
Thread.Sleep(30000);
}
}
Here I'm updating timestamp for every user in dt
void UvalClockTaksAsync()
{
foreach (DataRow row in users.Rows)
{
if (Convert.ToDouble(row[uvaltimePost]) < TimeCurrent)
row[uvaltimePost] = TimeCurrent;
}
}
And here I do the saving
void WriteTaskAsync(DataTable dt, bool final)
{
try
{
dt.WriteXml(filePath + "users.xml_be");
File.Replace(#$"{filePath}users.xml_be", #$"{filePath}users.xml", #$"{filePath}users.xml_be2");
if (final)
exiting = true;
}
catch (Exception ex)
{
try
{
File.AppendAllText($"{filePath}log.txt", $"{DateTime.Now.ToString()} {ex.Message}" + Environment.NewLine);
File.AppendAllText($"{filePath}log.txt", $"{ex.StackTrace}" + Environment.NewLine);
File.AppendAllText($"{filePath}log.txt", "////////////////////////////////////////////////////////////////" + Environment.NewLine);
}
catch (Exception)
{
client.SendMessage(tChannel, ErrorMes1);
client.SendMessage(tChannel, $"{ex.Message}|{ex.StackTrace}");
}
}
}
And it still not saving every time and the weirdest thing is that files users.xml and users.xml_be are not the same! Users timestamps are always different by 10s seconds. I mean wtf
If the file has a large volume of data, it could take time to write in a physical path. So can you increase the timeline (Thread.Sleep(10000);)
Related
I got this weird exception:
Collection was modified; enumeration operation might not execute.
This is my code:
void WriteTask(DataTable dt, string outputFilePath, bool final)
{
if (final)
{
exiting = false;
dbWriteTime = 0;
}
while (!exiting)
{
if (TimeCurrent - dbWriteTime >= 10)
{
try
{
dbWriteTime = TimeCurrent;
dt.WriteXml(outputFilePath + "users.xml");
if (final)
exiting = true;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine(ex.StackTrace);
}
}
Thread.Sleep(1000);
}
}
This is a task that every 10 seconds writes datatable to a file. I have searched this exception online, what I can find is that this exception occurs in a foreach loop if the collection has been changed. But I'm not using foreach.
I am coding a Forex Trading robot, and I am running an outOfMemory exception after some time (around 2 hours) using BlockingCollection.
I basically have 1 queue pair Trade chart, that are added into a dict:
private Dictionary<string, BlockingCollection<tick>> tickQueues = new Dictionary<string, BlockingCollection<tick>>();
I check the memory dump after one hour, and I can see the following items are piling up:
Count Size(bytes) Inclusive Size
ThreadPoolWorkQueue+QueueSegment 22,951 24,236,256 40,316,868
QueueUserWorkItemCallback 689,838 13,796,760 16,081,272
TimerQueueTimer 11,160 713,772 2,355,736
I have a timer that is responsible to add data to the Queue:
private void TickTimer_tick(object source, ElapsedEventArgs e) {
if (Monitor.TryEnter(LockTimerTick, GlobalSettings.APISleepDelayMSTick)) {
updateLockFailCount = 0;
try {
tick t = new tick(DateTime.Now, d.bid, d.ask);
lastBid = d.bid;
lastAsk = d.ask;
t.pair = Inst.pair;
//myTickQueue.TryAdd(t);
if (!myTickQueue.TryAdd(t)) {
functions.Logger.log("Error when adding Tick on Queue for " + Inst.pair+ " Maybe Queue is full", "SHMAPI", LOGLEVEL.WARN);
}
} catch (Exception E) {
functions.Logger.log("Error happened when refreshing tick data: " + E.Message, "SHMAPI", LOGLEVEL.ERROR);
} finally {
Monitor.Exit(LockTimerTick);
}
} else {
updateLockFailCount++;
int sev = LOGLEVEL.TRACE;
if (updateLockFailCount == 10) { sev = LOGLEVEL.DEBUG; }
if (updateLockFailCount==50) { sev = LOGLEVEL.WARN; }
if (updateLockFailCount % 100 == 0 && updateLockFailCount>=100) { sev = LOGLEVEL.ERROR; }
functions.Logger.log("Could not get lock to refresh tick data for symbol "+Symbol, "SHMAPI", sev);
}
}
And finally, my task that checks the Q:
public void startQueueTask(string Pair) {
if (!tickQueues.ContainsKey(Pair.ToUpper())) {
tickQueues.Add(Pair.ToUpper(), new BlockingCollection<tick>(GlobalSettings.tickQueueSize));
if (!MTAPIs.ContainsKey(Pair.ToUpper())) {
throw new Exception("API for pair " + Pair + " Should be initialized !!");
}
MTAPIs[Pair.ToUpper()].setTickQueue(tickQueues[Pair.ToUpper()]);
functions.Logger.log("Starting " + Pair + " Queue Task", "TICKPROCESSING", LOGLEVEL.DEBUG);
Task.Run(() => {
foreach (tick tick in tickQueues[Pair.ToUpper()].GetConsumingEnumerable()) {
try {
onTick(tick);
} catch (Exception E) {
functions.Logger.log("Error processing tick for symbol " + tick.pair + " " + E.Message, "TICKPROCESSING", LOGLEVEL.ERROR);
functions.printException(E);
}
}
functions.Logger.log("Exiting Queue Task", "TICKPROCESSING", LOGLEVEL.ERROR);
});
} else {
functions.Logger.log("Skipping " + Pair + " Queue Task because already exists", "TICKPROCESSING", LOGLEVEL.DEBUG);
}
}
I am not really sure why I am getting OOM, but it looks similar to:
http://blogs.microsoft.co.il/bnaya/2012/02/26/real-life-story-blocking-collection/
But I am not using parallel here... My Queues are empty though since week end market is closed.
Would using another timer with TryDequeue a better approach ?
Any advice would be welcome !
I switched timer to manual like this:
private void TickTimer_tick(object source, ElapsedEventArgs e) {
try {
//...
} finally {
TickTimer.Start();
}
}
And it seemed to have resolved my issue.
I am also making sure to send ticks in the Q, and they are filtered by duplicates by the Receiver, just so the Queing thread is never pending for too long as well.
Thanks for the pointer !
This is really short question. I don't understand try-catch mechanism completely.
This is my current code:
public static void WriteText(string filename, string text)
{
try
{
System.IO.StreamWriter file = new System.IO.StreamWriter(filename);
file.Write(text);
file.Close();
}
catch(Exception exc)
{
MessageBox.Show("File is probably locked by another process.");
}
}
Background:
Im writing application that shares configuration files with another application.
I need some dialog messagebox with "retry" and "abort" buttons, when that file is used by other application. When that message will appear - I will close that other application and I will try to rewrite that file again by pressing "Retry" button.
Whatr we have is using a counter for re-tries and possibly a thread sleep.
So something like
int tries = 0;
bool completed = false;
while (!completed)
{
try
{
System.IO.StreamWriter file = new System.IO.StreamWriter(filename);
file.Write(text);
file.Close();
completed = true;
}
catch(Exception exc)
{
tries++;
//You could possibly put a thread sleep here
if (tries == 5)
throw;
}
}
Even though there's a good answer already I'll submit one that's more tuned towards the OP's question (let the user decide instead of using a counter).
public static void WriteText(string filename, string text)
{
bool retry = true;
while (retry)
{
try
{
System.IO.StreamWriter file = new System.IO.StreamWriter(filename);
file.Write(text);
file.Close();
retry=false;
}
catch(Exception exc)
{
MessageBox.Show("File is probably locked by another process.");
// change your message box to have a yes or no choice
// yes doesn't nothing, no sets retry to false
}
}
}
If you need more info on how to implement the messagebox check out the following links;
http://msdn.microsoft.com/en-us/library/0x49kd7z.aspx
MessageBox Buttons?
I would do it like that:
public static void WriteText(string filename, string text, int numberOfTry = 3, Exception ex = null)
{
if (numberOfTry <= 0)
throw new Exception("File Canot be copied", ex);
try
{
var file = new System.IO.StreamWriter(filename);
file.Write(text);
file.Close();
}
catch (Exception exc)
{
WriteText(filename,text,--numberOfTry,ex);
}
}
I like it more like this (example tries to save a RichTextBox on close and allows retrying save or aborting close):
protected override void OnClosing(CancelEventArgs e)
{
if (richTextBox_Query.Modified)
{
DialogResult result;
do
try
{
richTextBox_Query.SaveFile(
Path.ChangeExtension(Application.ExecutablePath, "sql"),
RichTextBoxStreamType.UnicodePlainText);
result = DialogResult.OK;
richTextBox_Query.Modified = false;
}
catch (Exception ex)
{
result = MessageBox.Show(ex.ToString(), "Exception while saving sql query",
MessageBoxButtons.AbortRetryIgnore);
e.Cancel = result == DialogResult.Abort;
}
while (result == DialogResult.Retry);
}
base.OnClosing(e);
}
I have several services and use threads to implement each one. The services are executed sequentially. Let me just pick up one for demo purpose.
services[1] = new RProcessing() { ConsoleInfoColor = ConsoleColor.Cyan };
success = services[1].Start();
if (success)
{
OutputUtils.WriteLogInfo("Service " + services[1].Name + " started...");
}
else
{
OutputUtils.WriteLogInfo("Service " + services[1].Name + " failed to start...");
previousStartup = false;
services[0].Stop();
}
Inside RProcessing.
public RProcessing()
{
worker = new Thread[1]; // Only one thread
for (int i = 0; i < 1; i++)
{
worker[i] = new Thread(new ThreadStart(ServiceLoop));
worker[i].Name = "R Thread_" + i.ToString();
}
// processing
}
public bool Start()
{
foreach (Thread t in worker)
t.Start();
return (true);
}
public bool Stop()
{
if (_isRunning)
{
_isRunning = false;
}
_isRunning = false;
base.Dispose();
WriteLogInfo("Shutdown of R Processor complete");
return (true);
}
public void ServiceLoop()
{
_isRunning = true;
WriteLogInfo("Starting ServiceLoop() for: " + Assembly.GetAssembly(typeof(RProcessing)).FullName);
string s;
while (_isRunning)
{
Thread.Sleep(500);
s = null;
try
{
WriteLogInfo(" processing "+s);
Thread.Sleep(864);// 24 hours.
}
catch (Exception ex)
{
WriteLogError("Thread " + Thread.CurrentThread.Name + " " + ex.ToString());
}
}
if (this._isRunning)
{
WriteLogInfo("Restarting thread due to failure...");
try
{
Thread.CurrentThread.Start();
}
catch (Exception ex)
{
WriteLogError("Error restarting thread... " + ex.ToString());
}
}
}
Only there is one thread, I want to finish it then go back the next service. However it is always inside the ServiceLoop. How can break it? Just call Stop()?
Well, comment is misleading. Thread will sleep for 864 milliseconds, and not 24 hours.
Thread.Sleep(864);// 24 hours.
If you really intend to sleep that long in a loop, then use ManualResetEvent so that you could abort the wait at any time.
ManualResetEvent cancelEvent;
in loop:
if(cancelEvent.WaitOne(TimeSpan.FromHours(24))){
break;
}
and, in Stop method:
cancelEvent.Set();
Also remove that:
if (this._isRunning)
{
WriteLogInfo("Restarting thread due to failure...");
try
{
Thread.CurrentThread.Start();
}
catch (Exception ex)
{
WriteLogError("Error restarting thread... " + ex.ToString());
}
}
And make sure that _isRunning is volatile, otherwise it may be cached and not updated in another thread. Your service will exit peacefully when you call Stop().
I've recently converted a TCP-port listening application into a Windows Service, which installs and runs perfectly on my 32bit Vista laptop.
The problem was, after its installation, which works, I attempted to run the service(through Remote Dekstop) on a 64bit Win7 and it neatly handed me an error 1053, basically stating that the service timed out while starting up.
Now I've gotten it to start up without errors, but all it does is exit immediately without any errors or any eventLogging past OnStart.
I've tried replacing my Timer with Threading to see if that might have been the issue with the strange start, but no luck there... Here's the OnStart method of the service and the method that is meant to run continously.
protected override void OnStart(string[] args)
{
myServer.Start();
eventLog1.WriteEntry("Server started.");
mWorker = new Thread(StartUp);
eventLog1.WriteEntry("Starting up CykelScore service.");
mWorker.Start();//Start the service
//timer.Start(); // Start the timer
}
private void StartUp(object arg)
{
while (true)
{
eventLog1.WriteEntry("Running.");
if (mStop.WaitOne(10000)) return;
{
if (Monitor.dataCount > 0)
{
string tmp = "";
eventLog1.WriteEntry("Antal tags: " + Monitor.dataCount.ToString());
lockedUp.WaitOne();
try
{
tmp = Monitor.PopData();
}
catch (Exception ex)
{
eventLog1.WriteEntry("Fejl:" + ex.ToString());
}
eventLog1.WriteEntry("Recieved: " + tmp);
string buffer = tmp;
string antenna = (buffer.Split(',')[0]).Replace(" ", "");
string time = buffer.Split(',')[2];
string RFIDNR = (buffer.Split(',')[1]).Replace(" ", "");
string[] ART = new string[3];
ART[0] = antenna;
ART[1] = RFIDNR;
ART[2] = time;
if (lastreceivedtagID == RFIDNR)
{
eventLog1.WriteEntry("Same tag as last time. No need to check database");
}
else
{
if (!DataHandler.LoggedInCurrentTimespan(ART))
{
try
{
DataHandler.SaveToLocal(ART);
eventLog1.WriteEntry("Data saved to local database");
DataHandler.SendToRemote(tmp, Monitor.server, Monitor.database, Monitor.username, Monitor.password);
eventLog1.WriteEntry("Data sent to remote database");
}
catch (Exception ex)
{
eventLog1.WriteEntry("Fejl" + ex.ToString());
}
}
else
eventLog1.WriteEntry("Discarding data. Already in local database");
}
lastreceivedtagID = RFIDNR;
lockedUp.ReleaseMutex();
}
}
}
}
Does anyone have any idea what might be the issue?