My C# multi-threaded console application seems to not be multithreaded - c#

Here's my C# console program that uses Powerpoint to convert ppt files to folders of pngs. This is supposed to be an automated process that runs on its own server.
I expect that as soon as a thread creates an image from a file, it should immediately remove the images and the source file.
The actual behavior is that, if five threads are running, it'll wait for five folders of images to be created before any thread can move any files. I'm able to see the images being created, and compare that with the Console readout, so I can see that a thread isn't trying to move the file.
Only after all the other threads have made their images, will any thread try to move the files. I suspect this is wrong.
This is an Amazon EC2 Medium instance, and it appears to max out the CPU, so five threads might be too much for this.
I also find that I can hardly use Windows Explorer while this program is running.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.IO;
using Microsoft.Office.Core;
using PowerPoint = Microsoft.Office.Interop.PowerPoint;
using System.Diagnostics;
using System.Timers;
namespace converter
{
class Program
{
public static int threadLimit=0;
public static int currThreads = 0;
static void Main(string[] args)
{
var inDir = args[0];
var outDir = args[1]+"\\";
var procDir = args[2]+"\\";
Int32.TryParse(args[3],out threadLimit);
Thread[] converterThreads = new Thread[threadLimit];
while (true)
{
System.Threading.Thread.Sleep(1000);
var filePaths = Directory.GetFiles(inDir, "*.*", SearchOption.AllDirectories).Where(s => s.EndsWith(".pptx") && !s.Contains("~$") || s.EndsWith(".ppt") && !s.Contains("~$"));
var arrPaths = filePaths.ToArray();
for(var i=0; i< arrPaths.Length; i++)
{
if (currThreads < threadLimit && currThreads < arrPaths.Length)
{
Console.WriteLine("currThreads= " + currThreads + " paths found= " + arrPaths.Length);
try
{
var fileNameWithoutExtension = arrPaths[currThreads].Replace(inDir, "").Replace(".pptx", "").Replace(".ppt", "").Replace("\\", "");
var filenameWithExtension = arrPaths[currThreads].Substring(arrPaths[currThreads].LastIndexOf("\\") + 1);
var dir = arrPaths[currThreads].Replace(".pptx", "").Replace(".ppt", "");
Conversion con = new Conversion(arrPaths[currThreads], dir, outDir, procDir, filenameWithExtension, fileNameWithoutExtension);
converterThreads[i] = new Thread(new ThreadStart(con.convertPpt));
converterThreads[i].Start();
Console.WriteLine(converterThreads[i].ManagedThreadId + " is converting " + fileNameWithoutExtension);
}
catch (Exception e)
{
Console.WriteLine(string.Format("Unable to convert {0} ", arrPaths[i]) + e);
}
}
}
for (var i = 0; i < converterThreads.Length; i++)
{
if (converterThreads[i] != null)
{
if (!converterThreads[i].IsAlive)
{
converterThreads[i].Abort();
converterThreads[i].Join(1);
Console.WriteLine("thread " + converterThreads[i].ManagedThreadId + " finished, "+currThreads+" remaining");
converterThreads[i] = null;
}
}
}
if (currThreads == 0)
{
try
{
foreach (Process proc in Process.GetProcessesByName("POWERPNT"))
{
proc.Kill();
}
}
catch (Exception e3)
{
}
}
}
}
}
class Logger{
static void toLog(String msg)
{
//TODO: log file
}
}
class Conversion{
static int numberOfThreads=0;
String input;
String output;
String outDir;
String process;
String nameWith;
String nameWithout;
int elapsedTime;
System.Timers.Timer time;
public Conversion(String input, String output, String outDir, String processDir, String nameWith, String nameWithout)
{
this.input = input;
this.output = output;
this.outDir = outDir;
process = processDir;
this.nameWith = nameWith;
this.nameWithout = nameWithout;
numberOfThreads++;
Console.WriteLine("number of threads running: " + numberOfThreads);
Program.currThreads = numberOfThreads;
time = new System.Timers.Timer(1000);
time.Start();
time.Elapsed += new ElapsedEventHandler(OnTimedEvent);
elapsedTime = 0;
}
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
elapsedTime++;
}
public void convertPpt()
{
var app = new PowerPoint.Application();
var pres = app.Presentations;
try
{
var file = pres.Open(input, MsoTriState.msoFalse, MsoTriState.msoFalse, MsoTriState.msoFalse);
file.SaveAs(output, Microsoft.Office.Interop.PowerPoint.PpSaveAsFileType.ppSaveAsPNG, MsoTriState.msoTrue);
file.Close();
app.Quit();
Console.WriteLine("file converted " + input);
}
catch (Exception e)
{
Console.WriteLine("convertPpt failed");
}
moveFile();
moveDir();
}
public void moveFile()
{
Console.WriteLine("moving" + input);
try
{
System.Threading.Thread.Sleep(500);
Console.WriteLine(string.Format("moving {0} to {1}", input, process + nameWith));
if (File.Exists(process + nameWith))
{
File.Replace(input, process + nameWith, null);
}
else
{
File.Move(input, process + nameWith);
}
}
catch (Exception e)
{
Console.WriteLine(string.Format("Unable to move the file {0} ", input) + e);
try
{
foreach (Process proc in Process.GetProcessesByName("POWERPNT"))
{
proc.Kill();
}
}
catch (Exception e3)
{
}
}
}
public void moveDir()
{
Console.WriteLine("moving dir " + output);
try
{
System.Threading.Thread.Sleep(500);
Console.WriteLine(string.Format("moving dir {0} to {1} ", output, outDir + nameWithout));
if (Directory.Exists(outDir + nameWithout))
{
Directory.Delete(outDir + nameWithout, true);
}
if (Directory.Exists(output))
{
Directory.Move(output, outDir + nameWithout);
}
}
catch (Exception e)
{
Console.WriteLine(string.Format("Unable to move the directory {0} ", output) + e);
try
{
foreach (Process proc in Process.GetProcessesByName("POWERPNT"))
{
proc.Kill();
}
}
catch (Exception e3)
{
}
}
finally
{
numberOfThreads--;
Program.currThreads = numberOfThreads;
Console.WriteLine("took " + elapsedTime + "seconds");
}
}
}
}

Every 1000ms you get a list of files in inDir and potentially start a thread to process each file. You have very complex logic surrounding whether or not to start a new thread, and how to manage the lifetime of the thread.
The logic is too complex for me to spot the error without debugging the code. However, I would propose an alternative.
Have a single thread watch for new files and place the file path into a BlockingCollection of files for processing. That thread does nothing else.
Have N additional threads that retrieve file paths from the BlockingCollection and process them.
This is known as a Producer / Consumer pattern and is ideal for what you are doing.
The example code at the bottom of the linked MSDN page shows an implementation example.
On a side note, you are catching and swallowing Exception e3. Don't catch something you will not handle, it hides problems.

Related

How to fix 'broken pipe' error when trying to write from NamedPipeClientStream to NamedPipeServerStream

I have a program, that has to comunicate with another program that is called from the first.
I have managed to send the required data from the first to the second program using NamedPipes.
When the second program closes, i need to send some data back to the first program. I set up a NamedPipeServerStream in the first program and from the Closing event of the second program a NamedPipeClientStream. Now when i try to write from ClientStream i get a broken pipe error.
This is the code from the first program:
private void CreateOverlay(object sender, EventArgs e)
{
if (oinstallfolder != null)
{
string processfilename = oinstallfolder.ToString() + "\\SecondProgram.exe";*/
string processfilename = "SecondProgram.exe";
if (File.Exists(processfilename))
{
foreach (Process clsProcess in Process.GetProcesses())
{
if (clsProcess.ProcessName.Equals("SecondProgram"))
{
this.threadHandleOverlayBounds = new Thread(new ThreadStart(this.ExchangeMapOverlayBoundsServer));
this.threadHandleOverlayBounds.Start();
this.threadHandleOverlayFile = new Thread(new ThreadStart(this.ExchangeMapOverlayFileServer));
this.threadHandleOverlayFile.Start();
ShowWindow(clsProcess.MainWindowHandle, SW_SHOWNORMAL);
SetForegroundWindow(clsProcess.MainWindowHandle);
return;
}
}
try
{
this.threadHandleOverlayBounds = new Thread(new ThreadStart(this.ExchangeMapOverlayBoundsServer));
this.threadHandleOverlayBounds.Start();
Logger.Logger.Write("Log.txt", "Starting Filethread serverside");
this.threadHandleOverlayFile = new Thread(new ThreadStart(this.ExchangeMapOverlayFileServer));
this.threadHandleOverlayFile.Start();
Process.Start(processfilename);
}
catch { }
}
}
}
private void ExchangeMapOverlayFileServer()
{
try
{
using (NamedPipeServerStream namedPipeServer = new NamedPipeServerStream("OverlayFilePipe", PipeDirection.In, 1, PipeTransmissionMode.Byte))
{
string line;
namedPipeServer.WaitForConnection();
StreamReader sr = new StreamReader(namedPipeServer);
line = sr.ReadLine();
namedPipeServer.Disconnect();
namedPipeServer.Close();
}
}
catch(Exception e)
{
Logger.Logger.Write("OverlayGenerator.txt", "namedPipeServer exception: " + e.Message + "\n" + e.StackTrace);
}
}
this is the code from the second program
this.Closing += (s, a) =>
{
Logger.Logger.Write("Log.txt", "Window Closing");
this.threadHandleOverlayFile = new Thread(new ThreadStart(this.HandleWindowClosing));
this.threadHandleOverlayFile.Start();
while (!done)
{
Thread.Sleep(100);
}
};
private void HandleWindowClosing()
{
if (!String.IsNullOrEmpty(this.latestSavedOverlayPath))
{
try
{
using (NamedPipeClientStream namedPipeClient = new NamedPipeClientStream(".", "OverlayFilePipe", PipeDirection.Out))
{
namedPipeClient.Connect();
StreamWriter sw = new StreamWriter(namedPipeClient);
sw.AutoFlush = true;
sw.WriteLine("testphrase");
namedPipeClient.Close();
this.done = true;
}
}
catch (Exception e) { Logger.Logger.Write("OverlayGenerator.txt", "Exception in Client: " + e.Message + "\n" + e.StackTrace); }
}
else
{
Logger.Logger.Write("OverlayGenerator.txt", "Latest saved OverlayPath = " + this.latestSavedOverlayPath);
}
}
I tried this with Autoflush=true and without. With it, i get a broken pipe exception at the line
sw.WriteLine("testphrase");
and without it, the client side just runs to the end and nothing happens at all.
Where is my mistake?
Thank you.
EDIT
OK, i just don't get it. I made a test program, that is build the same way as the actual one. Two applications, the first starting the second. I start the pipe server in a thread in the first application and the client, also in a thread, in the second. The only difference is, that i run this test project in debug mode, which i can't do for the actual program. Now, in the test program, this matter is realy simple and it works. When i use the exact same approach in the actual program, it doesn't work.
In the testprogram i need to use flush on the streamwriter and i don't get an exception. The syncronization of the threads gets handled by the pipe itself, as it should be if i understood this correctly.
The Master looks like this:
private const string CLIENTPROC = "C:\\Users\\Maik\\Source\\Repos\\PipeTest\\PipeClient\\obj\\x86\\Release\\PipeClient.exe";
private ManualResetEvent threadResetEvent;
private Thread threadHandlePipeSendLast;
private Process procClient;
private string msgPipeSend;
private volatile bool bMsgPipeSend;
public MainWindow()
{
InitializeComponent();
this.threadResetEvent = new ManualResetEvent(false);
System.Diagnostics.Debug.WriteLine("### starting thread");
this.threadHandlePipeSendLast = new Thread(new ThreadStart(this.ExchangeMapOverlayFileServer));
this.threadHandlePipeSendLast.Start();
}
private void ExchangeMapOverlayFileServer()
{
System.Diagnostics.Debug.WriteLine("server thread started");
Thread.CurrentThread.Name = "apocalypse";
try
{
using (NamedPipeServerStream namedPipeServer = new NamedPipeServerStream("ClosingPipe", PipeDirection.In, 1, PipeTransmissionMode.Byte))
{
string line;
namedPipeServer.WaitForConnection();
StreamReader sr = new StreamReader(namedPipeServer);
Thread.Sleep(100);
line = sr.ReadLine();
handleRecvMsgFromPipe(line);
namedPipeServer.Disconnect();
namedPipeServer.Close();
}
}
catch (Exception e)
{
System.Diagnostics.Debug.WriteLine("### " + e.Message + "\n" + e.StackTrace);
}
}
private void handleRecvMsgFromPipe(string line)
{
this.outbox.Text = line;
}
private void buttonOpenFormClient_Click(object sender, EventArgs e)
{
#if DEBUG
#else
if (this.procClient == null)
{
try
{
this.procClient = Process.Start(new ProcessStartInfo(CLIENTPROC));
}
catch (Exception exc)
{
MessageBox.Show(exc.Message, "Error");
}
}
#endif
}
}
And that's the client side:
private ManualResetEvent threadResetEvent;
private Thread threadHandlePipeSendLast;
private string msgPipeSend;
private volatile bool bMsgPipeSend;
private bool done;
public MainWindow()
{
InitializeComponent();
this.threadResetEvent = new ManualResetEvent(false);
this.Closing += (s, a) =>
{
System.Diagnostics.Debug.WriteLine("+++ FormClosing started.");
this.threadHandlePipeSendLast = new Thread(new ThreadStart(this.HandleWindowClosing));
this.threadHandlePipeSendLast.Start();
while (!done)
{
Thread.Sleep(1000);
}
};
}
private void HandleWindowClosing()
{
try
{
using (NamedPipeClientStream namedPipeClient = new NamedPipeClientStream(".", "ClosingPipe", PipeDirection.Out))
{
namedPipeClient.Connect();
StreamWriter sw = new StreamWriter(namedPipeClient);
//sw.AutoFlush = true;
sw.WriteLine("last message");
namedPipeClient.WaitForPipeDrain();
namedPipeClient.Close();
this.done = true;
}
}
catch (Exception e) { System.Diagnostics.Debug.WriteLine(e.Message + "\n" + e.StackTrace); }
}
Can anyone tell me, why this works in the test app and not in the actual one? I also tried various things from Thread.Sleep(x) at different points in the programs over Thread.Join() to pipe methods like WaitForPipeDrain (which is just ignored).

Application inexplicably failing capturing screenshots

I have an odd issue that I have been trying to pin down for awhile. Essentially my application opens up various URL's using chrome (data from an array), takes a picture of them, saves them, and continues on looping through the array. The application successfully launches and runs, but variably it fails (usually between 2-5 days). When it fails, chrome no longer appears to open but the application continues to 'run'. Here is the error that is being produced from my try/catches:
at System.Drawing.Graphics.CopyFromScreen(Int32 sourceX, Int32 sourceY, Int32 destinationX, Int32 destinationY, Size blockRegionSize, CopyPixelOperation copyPixelOperation)
at Command_Center_Screen_Capture_Agent.Form1.Capture(String name)
My only working theory right now is that there might be an issue with the memory since it's failing to take the picture and failing to open the browser, but I'm not sure how to test that theory.
{UPDATE} Going through the logs on all of my servers, I noticed that while only some had the error above, all of them had the following error:
at System.Drawing.Image.Save(String filename, ImageCodecInfo encoder, EncoderParameters encoderParams)
at System.Drawing.Image.Save(String filename, ImageFormat format)
at Command_Center_Screen_Capture_Agent.Form1.Capture(String name) in SERVER REDACTED\Visual Studio 2012\Projects\Command Center Screen Capture Agent\Command Center Screen Capture Agent\Form1.cs:line 170
This error appears to always be the last error before the system stopped logging and (theoretically) failed.
The code in question is:
try
{
GFX.CopyFromScreen(Screen.PrimaryScreen.Bounds.X,
Screen.PrimaryScreen.Bounds.Y,
0,
0,
Screen.PrimaryScreen.Bounds.Size,
CopyPixelOperation.SourceCopy);
}
catch (Exception e)
{
//Noticed without this if the program was running before skyvision was opened an occasional error popped up
error_logging(e.StackTrace);
}
// Save the screenshot to the specified path
try
{
String filePath = #"\" + pictureNames[count] + ".png";
// MessageBox.Show("Saving file to: " + FILEPATH_LOCATION + forTesting);
BIT.Save(#FILEPATH_LOCATION + #filePath, ImageFormat.Png);
System.Threading.Thread.Sleep(2000);
count++;
_capture.Enabled = true;
}
catch (Exception e)
{
error_logging(e.StackTrace);
//Save error without breaking in case issue with path
//MessageBox.Show("CAPTURE ERROR: \n\n" + e.StackTrace);
}
The full source code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Drawing.Imaging;
using System.Diagnostics;
using System.IO;
using System.Configuration;
namespace Command_Center_Screen_Capture_Agent
{
public partial class Form1 : MaterialSkin.Controls.MaterialForm
{
public Form1()
{
InitializeComponent();
}
//Array storage for URLs and pic names
public static String[] URLS;
public static String[] pictureNames; //Used to save picture by name
//Data
static List<String> URL_LIST = new List<String>();
static List<String> URL_DESC = new List<String>();
static String base_url_1 = "URL_OMITTED";
static String base_url_2 = "URL_OMITTED";
static Configuration configManager = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
int count = 0;
//Create a new bitmap.
static Image BIT = new Bitmap(Screen.PrimaryScreen.Bounds.Width,
Screen.PrimaryScreen.Bounds.Height,
PixelFormat.Format32bppArgb);
// Create a graphics object from the bitmap.
Graphics GFX = Graphics.FromImage(BIT);
string FILEPATH_LOCATION = (#"FILEPATH_OMITTED");
string ERROR_LOGGING = Path.Combine(Application.StartupPath, "Error Logs");
private void error_logging(string line)
{
try
{
Guid filename = Guid.NewGuid();
string targetPath = Path.Combine(ERROR_LOGGING, filename + ".txt");
using (System.IO.StreamWriter file =
new System.IO.StreamWriter(targetPath))
{
file.WriteLine(line);
}
}
catch (Exception E)
{
MessageBox.Show("Failure Writing Error log. " + E.StackTrace);
}
}
private void load_data()
{
//Attempt to load data
try
{
string line;
System.IO.StreamReader file =
new System.IO.StreamReader(AppDomain.CurrentDomain.BaseDirectory + "data.txt");
while ((line = file.ReadLine()) != null)
{
if (line.Contains("SERVERS:"))
{
URL_LIST = line.Substring(8).Split(',').ToList();
}
if (line.Contains("DESC:"))
{
URL_DESC = line.Substring(5).Split(',').ToList();
}
}
file.Close();
}
catch (Exception criticalError)
{
MessageBox.Show("Critical Error. Could not access data file. Closing application. \n\n" + criticalError.StackTrace);
Application.Exit();
}
}
private void build_error_log()
{
if (!Directory.Exists(ERROR_LOGGING))
{
Directory.CreateDirectory(ERROR_LOGGING);
}
}
private void Form1_Load(object sender, EventArgs e)
{
build_error_log();
load_data();
Checkpath();
cycleTimeTxtBx.Text = Properties.Settings.Default.TimeToLoadPage.ToString();
}
private bool Checkpath()
{
this.Hide();
if (Directory.Exists(FILEPATH_LOCATION))
{
return (true);
}
else
{
DirectoryInfo dir = Directory.CreateDirectory(FILEPATH_LOCATION);
return false;
}
}
private void Capture(string name)
{
try
{
if (!Checkpath())
{
System.Threading.Thread.Sleep(1000);
}
}
catch (Exception whoops)
{
error_logging(whoops.StackTrace);
//Console.WriteLine(whoops);
}
// Take the screenshot from the upper left corner to the right bottom corner.
try
{
GFX.CopyFromScreen(Screen.PrimaryScreen.Bounds.X,
Screen.PrimaryScreen.Bounds.Y,
0,
0,
Screen.PrimaryScreen.Bounds.Size,
CopyPixelOperation.SourceCopy);
}
catch (Exception e)
{
error_logging(e.StackTrace);
}
// Save the screenshot to the specified path
try
{
String filePath = #"\" + pictureNames[count] + ".png";
BIT.Save(#FILEPATH_LOCATION + #filePath, ImageFormat.Png);
System.Threading.Thread.Sleep(2000);
count++;
_capture.Enabled = true;
}
catch (Exception e)
{
error_logging(e.StackTrace);
//Save error without breaking in case issue with path
//MessageBox.Show("CAPTURE ERROR: \n\n" + e.StackTrace);
}
KillChrome();
}
private void KillChrome()
{
try
{
Process[] procsChrome = Process.GetProcessesByName("chrome");
foreach (Process pro in procsChrome)
{
pro.Kill();
}
}
catch (Exception e)
{
error_logging(e.StackTrace);
Console.WriteLine(e);
}
}
private void _capture_Tick(object sender, EventArgs e)
{
//Assume that the URL array hasn't been setup
if (URLS == null || URLS.Length < 1)
{
URLS = URL_LIST.ToArray();
pictureNames = URL_DESC.ToArray();
}
try
{
Process process = new Process();
process.StartInfo.FileName = "chrome.exe";
if (count < URLS.Length)
{
string sysCode = URLS[count];
string market;
int delimIndex = sysCode.IndexOf("|");
market = sysCode.Substring(delimIndex + 1);
sysCode = sysCode.Substring(0, delimIndex);
string useable_url = base_url_1 + sysCode + base_url_2 + market;
process.StartInfo.Arguments = useable_url + " --start-maximized --incognito --new-window";
}
else
{
count = 0;
string sysCode = URLS[count];
string market;
int delimIndex = sysCode.IndexOf("|");
market = sysCode.Substring(delimIndex + 1);
sysCode = sysCode.Substring(0, delimIndex);
string useable_url = base_url_1 + sysCode + base_url_2 + market;
process.StartInfo.Arguments = useable_url + " --start-maximized --incognito --new-window";
}
process.Start();
_capture.Enabled = false;
System.Threading.Thread.Sleep(Properties.Settings.Default.TimeToLoadPage * 1000);
Capture("no");
}
catch (Exception error)
{
error_logging(error.StackTrace);
//MessageBox.Show(error.StackTrace);
}
}
private void startBTN_Click(object sender, EventArgs e)
{
_capture.Enabled = true;
this.Hide();
notifyIcon1.Visible = true;
}
private void saveBtn_Click(object sender, EventArgs e)
{
try
{
Properties.Settings.Default.TimeToLoadPage = Convert.ToInt32(cycleTimeTxtBx.Text);
Properties.Settings.Default.Save();
}
catch (Exception error)
{
MessageBox.Show("Error: Unable to parse cycle timer. Please only use integers when setting the cycle time.", "Parsing Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
cycleTimeTxtBx.Text = Properties.Settings.Default.TimeToLoadPage.ToString();
}
}
private void notifyIcon1_MouseDoubleClick(object sender, MouseEventArgs e)
{
Console.WriteLine("Clicked");
Show();
_capture.Enabled = false;
this.WindowState = FormWindowState.Normal;
notifyIcon1.Visible = false;
}
}
}

C# Multithreading for three threads working in parallel and sending data to each other and working in order

I have a C# windows form program that uses three threads.
*The first thread is responsible for reading files from input folder and reading all text from each file then send data as string to the second thread using a Queue.
*The second thread is responsible on parsing the string got from the first thread, if the string was a number then send this number to the third thread also using a Queue.
*The third thread is responsible on creating file for the number got from thread 2.
Also I should have a Timer that runs thread 1 every 4 seconds for example until pressing stop.( should thread 2 and thread 3 when thread 1 runs after 4 seconds ?)
Note That the three threads should be running in parallel and should be in the correct order Thread 1 then Thread 2 then Thread 3 and should be getting and sending data for each other.
Below is an image for what i described below and some of the code that I used in my program.
Please I want your help I'm stuck in this ....
Code is :
form1.cs Class
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Mltithreading
{
public partial class Form1 : Form
{
public ConcurrentQueue<string> _queue = new ConcurrentQueue<string>();
public Queue<string> Queue1result = new Queue<string>();
public Queue<string> TestQueue = new Queue<string>();
public Queue<string> Queue2result = new Queue<string>();
public Form1()
{
InitializeComponent();
}
/* private Timer timer1;
public void InitTimer()
{
timer1 = new Timer();
timer1.Tick += new EventHandler(timer1_Tick);
timer1.Interval = 2000; // in miliseconds
timer1.Start();
} */
private void timer1_Tick(object sender, EventArgs e)
{
isonline();
}
public void isonline()
{
//
// The user selected a folder and pressed the OK button.
// We print the number of files found.
//
string[] files = Directory.GetFiles(folderBrowserDialog1.SelectedPath);
MessageBox.Show(files[0]);
var a = files[1];
var dir = new DirectoryInfo(folderBrowserDialog1.SelectedPath);
FileInfo[] f = dir.GetFiles();
foreach (System.IO.FileInfo fi in f)
{
Console.WriteLine("{0}: {1}: {2}", fi.Name, fi.LastAccessTime, fi.Length);
}
MessageBox.Show("Files found: " + files.Length.ToString(), "Message");
}
private void button1_Click(object sender, EventArgs e)
{
DialogResult result = folderBrowserDialog1.ShowDialog();
if (result == DialogResult.OK)
{
//
// The user selected a folder and pressed the OK button.
// We print the number of files found.
//
textBox1.Text = folderBrowserDialog1.SelectedPath;
/* try
{
string[] files = Directory.GetFiles(folderBrowserDialog1.SelectedPath);
var dir = new DirectoryInfo(folderBrowserDialog1.SelectedPath);
var output = folderBrowserDialog2.SelectedPath;
FileInfo[] f = dir.GetFiles();
Queue<FileInfo> Q = new Queue<FileInfo>(f);
while (Q.Count > 0)
{
FileInfo current = Q.Dequeue();
Console.WriteLine(current);
// Process 'current'
}
foreach (System.IO.FileInfo fi in f)
{
Console.WriteLine("{0}: {1}: {2}", fi.Name, fi.LastAccessTime, fi.Length);
}
MessageBox.Show("Files found: " + files.Length.ToString(), "Message");
}
catch (Exception excep)
{
Console.WriteLine("An error occurred: '{0}'", excep);
} */
}
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void button2_Click(object sender, EventArgs e)
{
DialogResult result = folderBrowserDialog2.ShowDialog();
if (result == DialogResult.OK)
{
//
// The user selected a folder and pressed the OK button.
// We print the number of files found.
//
textBox2.Text = folderBrowserDialog2.SelectedPath;
}
}
private void button3_Click(object sender, EventArgs e)
{
string input = folderBrowserDialog1.SelectedPath;
string output = folderBrowserDialog2.SelectedPath;
var result = Thread1Start(input, output);
Console.WriteLine("Is thread Still Running :{0}", result);
//var firstThread = new Thread1();
var secondThread = new Thread2();
var thirdThread = new Thread3();
//Thread thread = new Thread(() => th.Readfiles(folderBrowserDialog1.SelectedPath, folderBrowserDialog2.SelectedPath));
//Thread thread1 = new Thread(delegate() { Queue1result = firstThread.Readfiles(folderBrowserDialog1.SelectedPath, folderBrowserDialog2.SelectedPath); });
//Thread thread3 = new Thread(() =>second.test(valueQueue));
Thread thread2 = new Thread(delegate() { Queue2result = secondThread.test(TestQueue); });
Thread thread3 = new Thread(() => thirdThread.CreateFiles(Queue2result,output));
//Thread thread5 = new Thread(second.run);
//thread1.Start();
// thread1.Join();
thread2.Start();
//thread2.Join();
thread3.Start();
//thread1.Start();
//thread1.Join();
//thread2.Start();
//thread1.Join(TimeSpan.Zero);
//Console.WriteLine(thread1.Join(TimeSpan.Zero));
// new System.Threading.Timer (ThreadTimer, "Thread 1 Started working...", 5000, 1000);
}
private void button4_Click(object sender, EventArgs e)
{
}
/* public void ThreadTimer (object data)
{
string input = folderBrowserDialog1.SelectedPath;
string output = folderBrowserDialog2.SelectedPath;
var result = Thread1Start(input, output);
Console.WriteLine("Is thread Still Running :{0}",result);
}
*/
public bool Thread1Start(string input, string output)
{
var firstThread = new Thread1();
Thread thread1 = new Thread(delegate() { Queue1result = firstThread.Readfiles(input, output); });
TestQueue = Queue1result;
thread1.Start();
Console.WriteLine("thread 1 start");
var state = thread1.Join(TimeSpan.Zero);
var secondThread = new Thread2();
var thirdThread = new Thread3();
//Thread thread = new Thread(() => th.Readfiles(folderBrowserDialog1.SelectedPath, folderBrowserDialog2.SelectedPath));
//Thread thread1 = new Thread(delegate() { Queue1result = firstThread.Readfiles(folderBrowserDialog1.SelectedPath, folderBrowserDialog2.SelectedPath); });
//Thread thread3 = new Thread(() =>second.test(valueQueue));
Thread thread2 = new Thread(delegate() { Queue2result = secondThread.test(Queue1result); });
Thread thread3 = new Thread(() => thirdThread.CreateFiles(Queue2result, output));
//Thread thread5 = new Thread(second.run);
//thread1.Start();
// thread1.Join();
thread2.Start();
//thread2.Join();
thread3.Start();
return state;
}
}
}
Thread1.cs class
here using System;
using System.IO;
using System.Text;
using System.Threading;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Mltithreading
{
class Thread1
{
public void run()
{
while (true)
{
int iterations = 10;
try
{
for (int i = 0; i < iterations; i++)
{
Console.WriteLine("From Thread 1");
Thread.Sleep(2000);
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
}
public Queue<string> Readfiles(string inputDirectoryPath, string outputDirectoryPath)
{ Queue<string> thread1Queue = new Queue<string>();
try
{
var dir = new DirectoryInfo(inputDirectoryPath);
FileInfo[] f = dir.GetFiles();
foreach (System.IO.FileInfo fi in f)
{
var filePath = fi.DirectoryName + "\\" + fi.Name;
//File.Copy(filePath, outputDirectoryPath + "\\" + fi.Name);
// Open the file to read from.
string readText = File.ReadAllText(filePath);
thread1Queue.Enqueue(readText);
Console.WriteLine(readText);
Console.WriteLine("thread 1 call read files method ");
//Console.WriteLine("{0}: {1}: {2}", fi.Name, fi.LastAccessTime, fi.Length);
}
}
catch (Exception excep)
{
Console.WriteLine("An error occurred: '{0}'", excep);
}
return thread1Queue;
}
}
}
Thread2.cs class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Mltithreading
{
class Thread2
{
public void run()
{
while (true)
{
int iterations = 10;
try
{
for (int i = 0; i < iterations; i++)
{
Console.WriteLine("From Thread 2");
Thread.Sleep(2000);
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
}
public Queue<string> test(Queue<string> list)
{
Queue<string> thread2Queue = new Queue<string>();
while (list.Count > 0)
{
try
{
var a = list.Dequeue();
Console.WriteLine(a);
int j;
if (Int32.TryParse(a, out j))
{
Console.WriteLine("parsed the string {0} to integer and sent to thread 3", j);
thread2Queue.Enqueue(a);
}
else
Console.WriteLine("String could not be parsed to integer.");
Console.WriteLine("thread 2 parsing string from thread 1");
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
return thread2Queue;
}
}
}
Thread3.cs Class
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Mltithreading
{
class Thread3
{
public void run()
{
while (true)
{
int iterations = 10;
try
{
for (int i = 0; i < iterations; i++)
{
Console.WriteLine("From Thread 3");
Thread.Sleep(2000);
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
}
public void CreateFiles(Queue<string> list, string outputDirectoryPath)
{
while (list.Count > 0)
{
string format = "MM-dd-yyyy--HH-mm-ss";
DateTime date = DateTime.Now;
string filename = date.ToString(format);
string file = outputDirectoryPath + "\\" + filename + ".txt";
var a = list.Dequeue();
FileInfo fi = new FileInfo(file);
if (!fi.Exists)
{
fi.Create().Dispose();
System.IO.File.WriteAllText(file,a);
Console.WriteLine("creating new text file {{0}}",file);
}
else
{
Console.WriteLine("file already exists");
}
Console.WriteLine(a);
Console.WriteLine("Thread 3 creating File with date name");
Console.WriteLine(date.ToString(format));
}
}
}
}
Thank you very much for your help .
I won´t comment on all, there´s too much stuff to talk about, but let´s have a look at your first thread.
Thread thread1 = new Thread(delegate() { Queue1result = firstThread.Readfiles(input, output); });
This line will create a thread that will replace the existing instance in your field Queue1Result (have a look at naming conventions, please!) once after reading some files (if existing). If executed again, The existing queue goes out of scope and will be replaced with a new one, probably not what you want to do.
You need to create those queue instances just once (type to use is ConcurrentQueue), those should then be used as a parameter running the thread procedure. So, redeclare the queues to readonly ConcurrentQueue to create the instances for your fields(give them a good "speaking" name, btw).
public readonly ConcurrentQueue<string> _textFromFilesQueue = new ConcurrentQueue<string>();
Once started, you want to regularly look after files again, so your code has to contain a loop.
This loop to be executed should be terminable from outside / other threads using a CancellationToken. Lets add a CancellationTokenSource to Form 1:
public CancellationTokenSource CancellationTokenSource { get; set; }
Your execution code for the first thread could / should look like this:
public void Readfiles(string inputDirectoryPath, string outputDirectoryPath, ConcurrentQueue<string> queue, CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
try
{
var dir = new DirectoryInfo(inputDirectoryPath);
FileInfo[] f = dir.GetFiles();
foreach (System.IO.FileInfo fi in f)
{
var filePath = Path.Combine(fi.DirectoryName, fi.Name);
//File.Copy(filePath, outputDirectoryPath + "\\" + fi.Name);
// Open the file to read from.
string textFromFile = File.ReadAllText(filePath);
queue.Enqueue(textFromFile);
Console.WriteLine(textFromFile);
Console.WriteLine("thread 1 call read files method ");
//Console.WriteLine("{0}: {1}: {2}", fi.Name, fi.LastAccessTime, fi.Length);
}
Thread.Sleep(TimeSpan.FromSeconds(5));
}
catch (Exception excep)
{
Console.WriteLine("An error occurred: '{0}'", excep);
Throw excep;
}
}
}
Do not build up a path by concatenating strings, use Path.Combine instead. Also, exceptions that happened should just be rethrown to ensure correct handling from other threads / tasks.
I would recommend using the TPL mechanisms instead of threads, it grants the system more flexibility in handling the tasks to be executed in a parallel manner. Have a look here : https://msdn.microsoft.com/de-de/library/dd460717(v=vs.110).aspx
So, creating and executing this task:
CancellationTokenSource = new CancellationTokenSource();
Task task = new Task(() => Readfiles(input, output, _textFromFilesQueue, CancellationTokenSource.Token));
task.Start();
Stopping the task:
CancellationTokenSource.Cancel();
Be sure not to overwrite the TokenSource without calling Cancel(), else you are losing the ability to stop the tasks that have already started...
EDIT: If you really need to ignore TPL, here is the example to execute the reading method with a thread:
Thread thread = new Thread(new ThreadStart(() => Readfiles(input, output, _textFromFilesQueue, CancellationTokenSource.Token)));
thread.Resume();
Use very simple and clear code:
var inputTexts = new BlockingCollection<string>();
var inputNumbers = new BlockingCollection<string>();
var readFiles = Task.Run(() =>
{
try
{
foreach (var file in Directory.EnumerateFiles("path", "searchPattern"))
{
string text = File.ReadAllText(file);
inputTexts.Add(text);
}
}
finally { inputTexts.CompleteAdding(); }
});
var processNumbers = Task.Run(() =>
{
try
{
foreach (var text in inputTexts.GetConsumingEnumerable())
{
int result;
if (int.TryParse(text, out result))
inputNumbers.Add(text);
}
}
finally { inputNumbers.CompleteAdding(); }
});
var createFiles = Task.Run(() =>
{
foreach (var number in inputNumbers.GetConsumingEnumerable())
{
string path = ""; // set fileName
File.WriteAllText(path, number);
}
});
Task.WaitAll(readFiles, processNumbers, createFiles);
It guarantees the execution in the correct order.
You can easily add cancellation using CancellationTokenSource.
Ok. Here is a working application that uses threads and timer.
It is assumed that execution all threads is faster than the timer interval.
New threads starts with each timer tick. The old threads will continue to work if they have not yet ended.
using System;
using System.Collections.Concurrent;
using System.IO;
using System.Threading;
using System.Windows.Forms;
namespace WindowsFormsApplication2
{
public partial class Form1 : Form
{
Button stopButton;
System.Windows.Forms.Timer timer;
public Form1()
{
//InitializeComponent();
stopButton = new Button { Parent = this, Text = "Stop" };
stopButton.Click += StopButton_Click;
timer = new System.Windows.Forms.Timer();
timer.Interval = 1000;
timer.Tick += Timer_Tick;
timer.Start();
Text = "Start";
}
private void StopButton_Click(object sender, EventArgs e)
{
timer.Stop();
Text = "Stop";
}
private void Timer_Tick(object sender, EventArgs e)
{
var inputTexts = new BlockingCollection<string>();
var inputNumbers = new BlockingCollection<string>();
var readFiles = new Thread(() =>
{
try
{
foreach (var file in Directory.EnumerateFiles("./Folder", "*.txt"))
{
string text = File.ReadAllText(file);
inputTexts.Add(text);
}
}
finally { inputTexts.CompleteAdding(); }
});
var processNumbers = new Thread(() =>
{
try
{
foreach (var text in inputTexts.GetConsumingEnumerable())
{
int result;
if (int.TryParse(text, out result))
inputNumbers.Add(text);
}
}
finally { inputNumbers.CompleteAdding(); }
});
var createFiles = new Thread(() =>
{
int counter = 0;
foreach (var number in inputNumbers.GetConsumingEnumerable())
{
File.WriteAllText("./Folder2/" + counter + ".txt", number);
counter++;
}
});
readFiles.Start();
processNumbers.Start();
createFiles.Start();
readFiles.Join();
processNumbers.Join();
createFiles.Join();
}
}
}

Winforms background worker gets stuck

I am trying to build a simple code that joins csv files into one distinct file, but my background worker seems to have a mind of its own and my code gets stuck every time.
Here is my code for joining the file using the background worker:
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
try
{
if (string.IsNullOrEmpty(saveFilePath))
{
this.Invoke(new MethodInvoker(delegate
{
btnBrowseSave.PerformClick();
}));
}
if (!string.IsNullOrEmpty(saveFilePath))
{
if (dragEventArgs != null)
files = (string[])dragEventArgs.Data.GetData(DataFormats.FileDrop);
int filesCount = 0, rowsCount = 0;
foreach (string file in files)
{
filesCount++;
int fileTotalLines = File.ReadAllLines(file).Length;
this.Invoke(new MethodInvoker(delegate
{
lblFileName.Text = "Loading file: " + file.Substring(file.LastIndexOf("\\") + 1);
lblTotalFiles.Text = "File " + filesCount + " of " + files.Length;
}));
using (StreamReader reader = new StreamReader(file))
{
using (StreamWriter writer = new StreamWriter(saveFilePath))
{
while (!reader.EndOfStream)
{
try
{
while (stopPosition > rowsCount)
{
reader.ReadLine();
rowsCount++;
}
string email = reader.ReadLine().Trim();
if (!string.IsNullOrEmpty(email) && !dicEmails.ContainsKey(email))
{
dicEmails.Add(email, null);
writer.WriteLine(email);
}
rowsCount++;
stopPosition++;
backgroundWorker.ReportProgress((rowsCount * 100 / fileTotalLines), (int)ProgressType.Row);
if (backgroundWorker.CancellationPending)
return;
}
catch (Exception ex)
{
hadReadErrors = true;
}
}
}
}
backgroundWorker.ReportProgress(0, (int)ProgressType.Row);
backgroundWorker.ReportProgress((filesCount * 100 / files.Length), (int)ProgressType.File);
}
}
}
catch (Exception ex)
{
hadReadErrors = true;
MessageBox.Show(ex.Message);
}
finally
{
backgroundWorker.Dispose();
}
}
private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
try
{
switch ((int)e.UserState)
{
case (int)ProgressType.Row:
lblFileProgress.Text = e.ProgressPercentage + "%";
fileProgressBar.Value = e.ProgressPercentage;
break;
case (int)ProgressType.File:
lblTotalProgress.Text = e.ProgressPercentage + "%";
totalProgressBar.Value = e.ProgressPercentage;
break;
}
}
catch (Exception ex) { }
}
When I run in debug mode and go with the debugger I don't see any problems, but when I let the code run it self it gets stuck and crashes.
Can someone PLEASE help me and tell me what am I missing out here ?
Here is the exception:
Managed Debugging Assistant 'ContextSwitchDeadlock' has detected a problem in
'C:\Users\Develop\Desktop\ExcelBuilder\ExcelBuilder\bin\Debug\ExcelBuilder.vshost.exe'.
Additional information: The CLR has been unable to transition from COM context 0x90fb78
to COM context 0x90fc30 for 60 seconds. The thread that owns the destination
context/apartment is most likely either doing a non pumping wait or processing a very
long running operation without pumping Windows messages. This situation generally has
a negative performance impact and may even lead to the application becoming non
responsive or memory usage accumulating continually over time. To avoid this problem,
all single threaded apartment (STA) threads should use pumping wait primitives
(such as CoWaitForMultipleHandles) and routinely pump messages during long running operations.
I did a small example of your program, trying to guess what it must do (https://github.com/anderson-rancan/stackoverflow_28798348, drag and drop 4 files to the groupbox, lorem?.csv), and there is a few things that you should consider:
never try/catch a unknown exception, every exception or something you cannot deal with (https://msdn.microsoft.com/en-us/library/ms182137.aspx)
when using a BackgroundWorker on a form, use the "sender" for references to it, it's a thread safe object to your method (https://msdn.microsoft.com/en-us/library/cc221403(v=vs.95).aspx)
maybe you are updating too fast your form, change your Invoke method to BeingInvoke, and do the update async (https://msdn.microsoft.com/en-us/library/0b1bf3y3(v=vs.110).aspx)
So, just fixing that was possible to run it, like this:
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker bckw = (BackgroundWorker)sender; // Recommended way, thread safe
try
{
if (string.IsNullOrEmpty(saveFilePath))
{
this.Invoke(new MethodInvoker(delegate
{
btnBrowseSave.PerformClick();
}));
}
if (!string.IsNullOrEmpty(saveFilePath))
{
if (dragEventArgs != null)
files = (string[])dragEventArgs.Data.GetData(DataFormats.FileDrop);
int filesCount = 0, rowsCount = 0;
foreach (string file in files)
{
filesCount++;
double fileTotalLines = File.ReadAllLines(file).Length;
this.BeginInvoke(new MethodInvoker(delegate
{
lblFileName.Text = "Loading file: " + file.Substring(file.LastIndexOf("\\") + 1);
lblTotalFiles.Text = "File " + filesCount + " of " + files.Length;
})); // Invoke async, way too fast this...
using (StreamReader reader = new StreamReader(file))
{
using (StreamWriter writer = new StreamWriter(saveFilePath))
{
while (!reader.EndOfStream)
{
try
{
while (stopPosition > rowsCount)
{
reader.ReadLine();
rowsCount++;
} // why are you using that? it won't get TRUE
string email = reader.ReadLine().Trim();
if (!string.IsNullOrEmpty(email) && !dicEmails.ContainsKey(email))
{
dicEmails.Add(email, null);
writer.WriteLine(email);
}
rowsCount++;
stopPosition++;
bckw.ReportProgress((int)Math.Round(rowsCount * 100 / fileTotalLines, 0), (int)ProgressType.Row);
if (bckw.CancellationPending)
return;
}
catch (Exception ex)
{
hadReadErrors = true;
throw; // Throw it again, or you won't know the Exception
}
}
}
}
bckw.ReportProgress(0, (int)ProgressType.Row);
bckw.ReportProgress((filesCount * 100 / files.Length), (int)ProgressType.File);
}
}
}
catch (Exception ex)
{
hadReadErrors = true;
MessageBox.Show(ex.Message);
}
finally
{
bckw.Dispose();
}
}
private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
//try
//{
switch ((int)e.UserState)
{
case (int)ProgressType.Row:
lblFileProgress.Text = e.ProgressPercentage + "%";
if (e.ProgressPercentage <= fileProgressBar.Maximum)
fileProgressBar.Value = e.ProgressPercentage;
break;
case (int)ProgressType.File:
lblTotalProgress.Text = e.ProgressPercentage + "%";
totalProgressBar.Value = e.ProgressPercentage;
break;
}
//}
//catch (Exception ex) { } // Don't catch everything
}
Finally, may I suggest another approach?
You're reading the file two times: one to get the number of lines, and another to read each line. Try to do this just once, you'll get a better result.

Streamreader locks file

I have a c# app (Windows Service) that fires a timer event that reads files in a directory and sends out SMS using the data in the files. Next time the event fires, it tries to move the processed files in the "Processed" directory to a "Completed" directory before processing the new files. I keep getting a "File in use by another process" exception, although I am pretty sure that I dispose of everything that uses the files. If I stop the service and start it again, the files is released. Any ideas?
//Code that fires the timer
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Timers;
namespace SmsWindowsService
{
public partial class SmsWindowsService : ServiceBase
{
private static System.Timers.Timer aTimer;
public SmsWindowsService()
{
InitializeComponent();
if (!System.Diagnostics.EventLog.SourceExists("MatterCentreSMSSource"))
{
System.Diagnostics.EventLog.CreateEventSource(
"MatterCentreSMSSource", "MatterCentreSMSLog");
}
elMatterCentreSMS.Source = "MatterCentreSMSSource";
elMatterCentreSMS.Log = "MatterCentreSMSLog";
}
protected override void OnStart(string[] args)
{
string logText = string.Empty;
logText = "MatterCentreSMS Service started successfully on " + DateTime.Now;
WriteEventLog(logText);
//Create a timer with a ten second interval.
aTimer = new System.Timers.Timer(10000);
//Hook up the Elapsed event for the timer.
aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
//Set the Interval to 5 minutes.
//aTimer.Interval = 300000;
aTimer.Interval = 60000;
aTimer.Enabled = true;
// If the timer is declared in a long-running method, use
// KeepAlive to prevent garbage collection from occurring
// before the method ends.
//GC.KeepAlive(aTimer);
GC.Collect();
}
protected override void OnStop()
{
string logText = string.Empty;
logText = "MatterCentreSMS Service stopped on " + DateTime.Now;
WriteEventLog(logText);
}
private void WriteEventLog(string logText)
{
elMatterCentreSMS.WriteEntry(logText);
}
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
string ex = string.Empty;
SendSms s = new SendSms();
ex = s.ProcessSms();
if (ex.Length > 1)
WriteEventLog(ex);
//ex = RestartService("SmsWindowsService", 60000);
//WriteEventLog(ex);
}
public string RestartService(string serviceName, int timeoutMilliseconds)
{
ServiceController service = new ServiceController(serviceName);
try
{
int millisec1 = Environment.TickCount;
TimeSpan timeout = TimeSpan.FromMilliseconds(timeoutMilliseconds);
service.Stop();
service.WaitForStatus(ServiceControllerStatus.Stopped, timeout);
// count the rest of the timeout
int millisec2 = Environment.TickCount;
timeout = TimeSpan.FromMilliseconds(timeoutMilliseconds - (millisec2 - millisec1));
service.Start();
service.WaitForStatus(ServiceControllerStatus.Running, timeout);
return "MatterCentreSMS Service successfully restarted on " + DateTime.Now;
}
catch (Exception e)
{
return Convert.ToString(e);
}
}
}
}
//Code that reads the file
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
namespace SmsWindowsService
{
class Message
{
private string filePath;
public Message(string filePath)
{
this.filePath = filePath;
}
public string readSMS(string filePath)
{
const string searchmessage = "[B-->]";
StreamReader smsmessage = new StreamReader(filePath);
try
{
FileInfo filenameinfo = new FileInfo(filePath);
if (filenameinfo.Exists == false)
throw new SMSReaderException(String.Format("SMS Message {0} cannot be found ...", filePath), filePath);
smsmessage = filenameinfo.OpenText();
string smsoutput = smsmessage.ReadToEnd();
int endpos = smsoutput.IndexOf(searchmessage);
smsoutput = smsoutput.Substring(endpos + searchmessage.Length);
smsoutput = smsoutput.Replace("&", "&");
smsoutput = smsoutput.Replace("\"", """);
smsoutput = smsoutput.Replace("'", "'");
filenameinfo = null;
smsmessage.Close();
smsmessage.Dispose();
return smsoutput;
}
catch(Exception e)
{
throw new Exception("Help", e.InnerException);
}
finally
{
smsmessage.Close();
smsmessage.Dispose();
}
}
}
public class SMSReaderException : System.IO.FileNotFoundException
{
public SMSReaderException(string message, string filename)
: base(message, filename)
{
}
}
}
//Code that connects to web service and send sms
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Data;
using System.IO;
using System.Net;
using System.Configuration;
using SmsWindowsService.EsendexSendSmsService;
namespace SmsWindowsService
{
class SendSms
{
string filePath = string.Empty;
string directoryPath = string.Empty;
string directoryPathProcessing = string.Empty;
string directoryPathCompleted = string.Empty;
string smsLogfileDirectory = string.Empty;
string smsLogfilePath = string.Empty;
string mattercentreSMS = string.Empty;
string messageBody = string.Empty;
string messageId = string.Empty;
string messageStatus = string.Empty;
string dateTodayString = string.Empty;
long mobileNumber;
EsendexSendSmsService.SendService send;
public SendSms()
{
directoryPath = ConfigurationSettings.AppSettings[#"directoryPath"];
directoryPathProcessing = ConfigurationSettings.AppSettings[#"directoryPathProcessing"];
directoryPathCompleted = ConfigurationSettings.AppSettings[#"directoryPathCompleted"];
smsLogfileDirectory = ConfigurationSettings.AppSettings[#"smsLogfileDirectory"];
dateTodayString = DateTime.Now.ToString("yyyy/MM/dd");
smsLogfilePath = smsLogfileDirectory + dateTodayString.Replace(#"/", "_") + ".txt";
send = new EsendexSendSmsService.SendService();
}
public string ProcessSms()
{
string ex = string.Empty;
try
{
DirectoryInfo di = new DirectoryInfo(directoryPathProcessing);
ex = MoveFilesToCompleted(directoryPathProcessing, directoryPathCompleted);
if (ex.Length > 1)
return ex;
ex = MoveFilesToProcessing(directoryPath, directoryPathProcessing);
if (ex.Length > 1)
return ex;
FileInfo[] subFilesProcessing = di.GetFiles();
foreach (FileInfo subFile in subFilesProcessing)
{
filePath = directoryPathProcessing + subFile.Name;
Message sms = new Message(filePath);
mattercentreSMS = sms.readSMS(filePath);
MessageDetails d = new MessageDetails(mattercentreSMS);
mobileNumber = d.GetMobileNumber();
messageBody = d.GetMessageBody();
ex = SetHeader();
if (ex.Length > 1)
return ex;
ex = SetProxy();
if (ex.Length > 1)
return ex;
//Send the message and get the returned messageID and send status
messageId = send.SendMessage(Convert.ToString(mobileNumber), messageBody, EsendexSendSmsService.MessageType.Text);
messageStatus = Convert.ToString(send.GetMessageStatus(messageId));
ex = WriteLogFile(messageId, subFile.Name, messageStatus);
if (ex.Length > 1)
return ex;
send.Dispose();
}
di = null;
subFilesProcessing = null;
return ex;
}
catch (Exception e)
{
return Convert.ToString(e);
}
}
private string MoveFilesToCompleted(string directoryPathProcessing, string directoryPathCompleted)
{
DirectoryInfo din = new DirectoryInfo(directoryPathProcessing);
try
{
FileInfo[] subFiles = din.GetFiles();
foreach (FileInfo subFile in subFiles)
{
subFile.MoveTo(directoryPathCompleted + subFile.Name);
}
subFiles = null;
return "";
}
catch (Exception e)
{
return Convert.ToString(e);
}
finally
{
din = null;
}
}
private string MoveFilesToProcessing(string directoryPath, string directoryPathProcessing)
{
DirectoryInfo din = new DirectoryInfo(directoryPath);
try
{
FileInfo[] subFiles = din.GetFiles();
foreach (FileInfo subFile in subFiles)
{
subFile.MoveTo(directoryPathProcessing + subFile.Name);
}
subFiles = null;
return "";
}
catch (Exception e)
{
return Convert.ToString(e);
}
finally
{
din = null;
}
}
private string SetHeader()
{
try
{
//Setup account details in the header
EsendexSendSmsService.MessengerHeader header = new EsendexSendSmsService.MessengerHeader();
header.Account = ConfigurationSettings.AppSettings[#"smsServiceUrl"];
header.Username = ConfigurationSettings.AppSettings[#"smsServiceUsername"];
header.Password = ConfigurationSettings.AppSettings[#"smsServicePassword"];
// set the SOAP header Authentication values
send.MessengerHeaderValue = header;
return "";
}
catch (Exception e)
{
return Convert.ToString(e);
}
}
private string SetProxy()
{
try
{
//Create a web proxy object as the proxy server block direct request to esendex
WebProxy myProxy = new WebProxy(ConfigurationSettings.AppSettings[#"proxyaddress"], true);
myProxy.Credentials = new NetworkCredential(ConfigurationSettings.AppSettings[#"username"], ConfigurationSettings.AppSettings[#"password"]);
WebRequest.DefaultWebProxy = myProxy;
send.Proxy = myProxy;
return "";
}
catch (Exception e)
{
return Convert.ToString(e);
}
}
private string WriteLogFile(string messageId, string smsFileName, string messageStatus)
{
try
{
if (File.Exists(smsLogfilePath))
{
//file is not empty - append log entry to file
using (StreamWriter writeSmsLog = File.AppendText(smsLogfilePath))
{
writeSmsLog.WriteLine(messageId + " " + smsFileName + " " + DateTime.Now + " " + messageStatus);
writeSmsLog.Close();
}
}
else
{
FileStream fs = File.OpenWrite(smsLogfilePath);
fs.Flush();
fs.Close();
fs.Dispose();
using (StreamWriter writeSmsLog = new StreamWriter(smsLogfilePath, true))
{
writeSmsLog.WriteLine("Message_ID File_Name Date_Sent Status");
writeSmsLog.WriteLine("======================================================================================================================================");
writeSmsLog.WriteLine(messageId + " " + smsFileName + " " + DateTime.Now + " " + messageStatus);
writeSmsLog.Close();
}
}
return "";
}
catch (Exception e)
{
return Convert.ToString(e);
}
}
}
}
Any ideas?
You're running a virus checker in an entirely different process. It is detecting that the file has changed and is locking it momentarily in order to check it to see if the edit you just performed to the file introduced a virus. It'll unlock it in a couple of milliseconds.
Disabling your virus checker is a bad idea. Instead, you're just going to have to live with it; write your code to be robust in a world where there are lots of processes vying for locks on files.
StreamReader smsmessage = new StreamReader(filePath);
try
{
FileInfo filenameinfo = new FileInfo(filePath);
....
smsmessage = filenameinfo.OpenText();
...
You are initializing smsmessage twice, but only disposing one of those instances. The first line constructs a StreamReader, and then you overwrite your reference to that instance with the instance created by filenameinfo.OpenText(). That leaves you with an instance that no longer has any references and hasn't been disposed. That instance might be holding a lock on the file and you have no guarantees on when it will be disposed. Even if it isn't holding a lock, you should still fix this.

Categories