Starting to use threads - c#

I'm trying to get my head around threads, in my current application threads would be the best way to deal with it, what i have:
public void threadsTest() {
Invoke(new MethodInvoker(() => {
// loop over the listview getting the first value
foreach (ListViewItem item in listViewBacklinks.Items)
{
// try...
try
{
var mainURL = item.Text;
using (WebClient wc = new WebClient())
{
try
{
var pageHtml = wc.DownloadString(mainURL);
if (pageHtml.Contains(Text))
{
var subitems = item.SubItems.Add("anchor text");
item.BackColor = Color.Green;
}
else
{
item.BackColor = Color.Red;
}
} catch (Exception)
{
item.BackColor = Color.Red;
}
//Helpers.returnMessage("Work done!");
}
} catch (Exception ex) {
Helpers.returnMessage(ex.ToString());
}
}}));
}
private void btnAnalyzeAnchorText_Click(object sender, EventArgs e)
{
// attempting threads
var t = new Thread(threadsTest);
t.Start();
}
I thought like the backgroundWorker it would not freeze up the GUI but it did so i put in the invoke to access GUI elements, i don't think it looks right, the way it is now the GUI is still unresponsive until the work is done, i have viewed some tutorials but it's not totally sinking in, any help/tips on cracking threads would be great.

This is what you need to do:
public void threadsTest(string[] urls)
{
var results = new Dictionary<string, string>();
foreach (string mainURL in urls)
{
using (WebClient wc = new WebClient())
{
var pageHtml = wc.DownloadString(mainURL);
results[mainUrl] = pageHtml;
}
}
Invoke(new MethodInvoker(() => ProcessResults(results)));
}
There are no UI elements in this code, just the heavy lifting of the WebClient.
Then in the new ProcessResults you're back on the UI thread so then you can set your results.
The call to the thread needs to pass through an array of urls (strings) but you get that before creating the thread so you're still in the UI thread and thus it is safe to do.

Related

Building a TreeView is causing my form to freeze

I'm trying to build an app that pulls back all the directories and files and builds a Treeview. I have some code below that does this, however it seams to cause my UI to freeze as it is building.
I'm unsure if this a threading issue? I think that the code that builds the tree view is on a separate thread to the UI although this is one bit i'm unsure of.
I've also read that i may need to look into UI Virtualisation / data Virtualisation. If anyone could point me into the correct direction that would be very helpful.
private void btnSearch_Click(object sender, System.EventArgs e)
{
btnSearch.Text = "Searching...";
this.Cursor = Cursors.WaitCursor;
Application.DoEvents();
Thread treeThread = new Thread(() => ListDirectory(lstTreeView, "C:\\"));
treeThread.Start();
btnSearch.Text = "Search";
this.Cursor = Cursors.Default;
}
private void ListDirectory(TreeView treeView, string path)
{
var watch = System.Diagnostics.Stopwatch.StartNew();
this.Invoke((MethodInvoker)(() => treeView.Nodes.Clear()));
var rootDirectoryInfo = new DirectoryInfo(path);
this.Invoke((MethodInvoker)(() => treeView.Nodes.Add(CreatedirNode(rootDirectoryInfo))));
watch.Stop();
var elapsedMs = watch.ElapsedMilliseconds;
this.Invoke((MethodInvoker)(() => lblCount.Items.Add("Time taken in Sec " + (elapsedMs)/1000)));
}
I think this maybe the reason as I think the UI is freezing as directoryNode.Nodes.Add(new TreeNode(file.Name)); looks to be writing on the UI thread?
private static TreeNode CreatedirNode(DirectoryInfo DirI) {
var directoryNode = new TreeNode(DirI.Name);
try
{
foreach (var directory in DirI.GetDirectories())
directoryNode.Nodes.Add(CreatedirNode(directory));
foreach (var file in DirI.GetFiles())
directoryNode.Nodes.Add(new TreeNode(file.Name));
}
catch (System.Exception excpt)
{
Console.WriteLine(excpt.Message);
}
return directoryNode;
}

Problems working with async Task and Textbox.Text = "Hello"

First of all, sorry because I am so new at C# and I decided to make this question because I have been choked in this for hours.
I have an GUI that works with Google Cloud Speech services and make a Speech-to-Text operation. I share with you the whole method that runs when a button is clicked:
private async Task<object> StreamingMicRecognizeAsync(int seconds)
{
if (NAudio.Wave.WaveIn.DeviceCount < 1)
{
Console.WriteLine("No microphone!");
return -1;
}
GoogleCredential googleCredential;
using (Stream m = new FileStream(#"..\..\credentials.json", FileMode.Open))
googleCredential = GoogleCredential.FromStream(m);
var channel = new Grpc.Core.Channel(SpeechClient.DefaultEndpoint.Host,
googleCredential.ToChannelCredentials());
var speech = SpeechClient.Create(channel);
var streamingCall = speech.StreamingRecognize();
// Write the initial request with the config.
await streamingCall.WriteAsync(
new StreamingRecognizeRequest()
{
StreamingConfig = new StreamingRecognitionConfig()
{
Config = new RecognitionConfig()
{
Encoding =
RecognitionConfig.Types.AudioEncoding.Linear16,
SampleRateHertz = 48000,
LanguageCode = "es-ES",
},
InterimResults = true,
}
});
// Read from the microphone and stream to API.
object writeLock = new object();
bool writeMore = true;
var waveIn = new NAudio.Wave.WaveInEvent();
waveIn.DeviceNumber = 0;
waveIn.WaveFormat = new NAudio.Wave.WaveFormat(48000, 1);
waveIn.DataAvailable +=
(object sender, NAudio.Wave.WaveInEventArgs args) =>
{
lock (writeLock)
{
if (!writeMore) return;
streamingCall.WriteAsync(
new StreamingRecognizeRequest()
{
AudioContent = Google.Protobuf.ByteString
.CopyFrom(args.Buffer, 0, args.BytesRecorded)
}).Wait();
}
};
// Print responses as they arrive.
Task printResponses = Task.Run(async () =>
{
while (await streamingCall.ResponseStream.MoveNext(default(CancellationToken)))
{
foreach (var result in streamingCall.ResponseStream
.Current.Results)
{
foreach (var alternative in result.Alternatives)
{
Console.WriteLine(alternative.Transcript);
//Textbox1.Text = alternative.Transcript;
}
}
}
});
waveIn.StartRecording();
Console.WriteLine("Speak now.");
Result_Tone.Text = "Speak now:\n\n";
await Task.Delay(TimeSpan.FromSeconds(seconds));
// Stop recording and shut down.
waveIn.StopRecording();
lock (writeLock) writeMore = false;
await streamingCall.WriteCompleteAsync();
await printResponses;
return 0;
}
My problem is that I want to update the content of the Textbox1control but it doesn´t work. It writes perfectly the output into the console with the line Console.WriteLine(alternative.Transcript); but not into my textbox.
If someone could help I would appreciate so much his help.
The problem is that you're using Task.Run, which means your code will be running on a thread-pool thread.
Instead of calling Task.Run(), just move that code into a separate async method:
async Task DisplayResponses(IAsyncEnumerator<StreamingRecognizeResponse> responses)
{
while (await responses.MoveNext(default(CancellationToken)))
{
foreach (var result in responses.Current.Results)
{
foreach (var alternative in result.Alternatives)
{
Textbox1.Text = alternative.Transcript;
}
}
}
}
Then call that method directly (without Task.Run) from code that's already on the UI thread (e.g. an event handler).
The async machinery will make sure that after the await expression, you're back on the UI thread (the same synchronization context). So the assignment to the Text property will occur on the UI thread, and all should be well.
For example:
// This would be registered as the event handler for a button
void HandleButtonClick(object sender, EventArgs e)
{
var stream = client.StreamingRecognize();
// Send the initial config request
await stream.WriteAsync(...);
// Presumably you want to send audio data...
StartSendingAudioData(stream);
await DisplayResponses(stream.ResponseStream);
}
Tasks run on seperate threads, so you must Invoke an action that will be performed on the control's thread
Textbox1.Invoke(new Action(() =>
{
Textbox1.Text= "";
}));
Edit: For WPF, I believe the equivalent is
Textbox1.Dispatcher.Invoke(new Action(() =>
{
Textbox1.Text= "";
}));
have you tried using Dispatcher.InvokeASync()?
await Dispatcher.InvokeAsync(() => {while (await streamingCall.ResponseStream.MoveNext(default(CancellationToken)))
{
foreach (var result in streamingCall.ResponseStream
.Current.Results)
{
foreach (var alternative in result.Alternatives)
{
Textbox1.Text = alternative.Transcript;
}
}
}});

C# increasing Memory on camera image processing

I have a problem with increasing memory. I have an image, that comes from a camera. The image is processed by a function with unmanaged code. If the expected pattern could not be found, this function takes a long time (some seconds). If the pattern can be found it returns a result very fast (some ms).
I tried to start the postprocessing in a new Thread and Abort it after 200ms. So far this works. Now I have the problem, that my memory grows. Maybe the using clause doesn't work as expected and the image is kept in memory...
private void ImageWorker()
{
while (_imageWorkerRunning)
{
try
{
using (var img = CameraHelper.GetImage())
{
var waiter = new ManualResetEvent(false);
ProcessResult result = null;
var thd = new Thread(() => {
result = UnManagedImageProcessor.Process(img);
waiter.Set();
});
thd.Start();
waiter.WaitOne(200);
if (thd.ThreadState == ThreadState.Running || result == null)
{
thd.Abort();
while (thd.ThreadState != ThreadState.Aborted) new ManualResetEvent(false).WaitOne(10);
}
Application.Current.Dispatcher.Invoke(() => DisplayImage = img);
}
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
}
}
Does the GC work fine on aborted Threads? I think maybe this is my problem...
Solutiuon:
I changed my code to the following. Now I have two parallel tasks. The first is getting images and check, if processing is available.
If it is, the image is provided to this ImageProcessing task. That displays image only on Success (then processing is fast and each picture can be processed).
If processing is not successfull it takes some time and the image is displayed only as live image (by ImageWorker).
private readonly object _imageLock = new object();
private ExtendedImage _sharedProcessingImage;
private readonly ManualResetEvent _processingWaiter = new ManualResetEvent(false);
private bool _processingWaits = false;
private void ImageWorker()
{
while (_imageWorkerRunning) {
try {
var img = CameraHelper.GetImage();
if (_processingWaits) {
//processing available --> process image
lock (_imageLock) {
_sharedProcessingImage = img;
}
_processingWaits = false;
_processingWaiter.Set();
}
else {
//Processing in progress --> Only display image
Application.Current.Dispatcher.Invoke(() => DisplayImage = img);
}
new ManualResetEvent(false).WaitOne(50);
}
catch (Exception e) {
_log.Error(e);
}
}
}
private void ImageProcessing()
{
while (_imageWorkerRunning) {
_processingWaits = true;
_processingWaiter.WaitOne();
_processingWaiter.Reset();
lock (_imageLock) {
try {
result = UnManagedImageProcessor.Process(_sharedProcessingImage);
// ... handle result
if(result.Succeeded) Application.Current.Dispatcher.Invoke(() => DisplayImage = _sharedProcessingImage);
}
catch (Exception e) {
_log.Error(e);
}
}
}
}
Thanks for your help.
What I propose to you is to use BlockingCollection.
To display the images you can use a locker, every time the UI is idle you lock the object, get the last image and dispose the previus one. Also, everytime a image is processed you lock the object and set the var to the last one.
Display logic:
readonly object lastProcessdImageLocker = new object();
Bitmap lastProcessdImage;
//Every time a image process is done:
lock(lastProcessdImageLocker)
lastProcessdImage = imageJustProcessed;
//Every time the UI thread is idle
lock(lastProcessdImageLocker)
myPictureboxImage = lastProcessdImage;
//Here you should also dispose the previus myPictureboxImage so you prevent your memory usage to grow fast!
See this post for more info about WPF and also WinForm render loop
Sample code of the use of BlockingCollection to consume (process) camera images:
BlockingCollection<Bitmap> cameraImages = new BlockingCollection<Bitmap>();
//use another theard to fill up the cameraImages, like that:
//cameraImages.Add(CameraHelper.GetImage());
void StartProcess()
{
if (processImageThread== null || !processImageThread.IsAlive)
{
processImageThread= new Thread(ProcessLoop);
processImageThread.Name = "ProcessLoop";
processImageThread.IsBackground = true;
processImageThread.Start();
Console.TraceInformation("ProcessLoop started");
}
}
private void ProcessLoop()
{
try
{
foreach (img in cameraImages.GetConsumingEnumerable(CancelProcessing.Token))
{
// Do your stuff
}
}
catch (OperationCanceledException)
{
Console.WriteLine("ProcessLoop OperationCanceledException.");
}
finally
{
}
}
If your cameraImages count grows too fast (getting out of memory), you need to reduce the process time or stop the camera for some time.

C# hang and stuck after Application.Run() at for loop

Im building a program that surf to several websites and do something.
After surfing to like 5 urls successfully, the program hangs after the Application.Run() line.
The program doesn't even enter the Handler function and just stuck. the CPU usage is 0 at this point.
I tried closing the threads in any possible way.
What i'm doing wrong?
I'm doing it like that:
[STAThread]
private static void Main(string[] args)
{
for (int i = 0; i < urls.Count; i++)
{
var th = new Thread(() = >
{
var weBrowser = new WebBrowser();
weBrowser.AllowNavigation = true;
weBrowser.DocumentCompleted += Handler;
weBrowser.Navigate(urls[i]);
Application.Run();
});
th.SetApartmentState(ApartmentState.STA);
th.Start();
th.Join();
}
}
And my Handle function is:
private static void Handler(object sender, WebBrowserDocumentCompletedEventArgs e)
{
WebBrowser weBrowser = sender as WebBrowser;
var htmlDocument = weBrowser.Document;
/*do something*/
Application.Exit();
Application.ExitThread();
weBrowser.Dispose();
weBrowser.Stop();
Thread.CurrentThread.Abort();
}
My problem is very similar to this one:
Application.Run() leads to application hanging
There is no answer in this question either.
Thanks!
I think you are doing several mistakes:
you are joining inside the for look
you are calling Application.Exit() in each handler call
You should move the joining outside the for loop and do not call Application.Exit.
The following sample seems to work well:
static class Program
{
[STAThread]
static void Main()
{
var urls = new List<string>() {
"http://stackoverflow.com",
"http://stackoverflow.com",
"http://stackoverflow.com",
"http://stackoverflow.com",
"http://stackoverflow.com",
"http://stackoverflow.com",
"http://stackoverflow.com",
"http://stackoverflow.com"};
var threads = new Thread[urls.Count];
for (int i = 0; i < urls.Count; i++)
{
threads[i] = new Thread((url) =>
{
var weBrowser = new WebBrowser();
weBrowser.AllowNavigation = true;
weBrowser.DocumentCompleted += Handler;
weBrowser.Navigate(url as string);
Application.Run();
});
threads[i].SetApartmentState(ApartmentState.STA);
threads[i].Start(urls[i]);
}
foreach (var t in threads)
t.Join();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
private static void Handler(object sender, WebBrowserDocumentCompletedEventArgs e)
{
WebBrowser weBrowser = sender as WebBrowser;
var htmlDocument = weBrowser.Document;
/*do something*/
Application.ExitThread();
weBrowser.Dispose();
weBrowser.Stop();
}
}
You may be running into the maximum number of concurrent connections for the WebBrowser. By explicitly setting this to a higher number, you can have additional streams reading through the browser at once.
// Example Usage:
ServicePointManager.DefaultConnectionLimit = 10;
Keep in mind that there is a performance hit by increasing this number above the default (I think it is 4) as you will have much more network traffic that needs processed.
See the MSDN article for ConnectionLimit for more information.
I don't understand what would you like to achieve with Application.Run inside for loop.
Why are you using WebBrowser component? If you are just parsing web page it is better to use
string urlAddress = "http://stackoverflow.com";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(urlAddress);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
if (response.StatusCode == HttpStatusCode.OK)
{
StreamReader reader= null;
if (response.CharacterSet == null)
reader = new StreamReader(response.GetResponseStream());
else
reader = new StreamReader(response.GetResponseStream(), Encoding.GetEncoding(response.CharacterSet));
string data = reader.ReadToEnd();
response.Close();
reader.Close();
}
or
using (WebClient client = new WebClient())
{
string html = client.DownloadString("http://stackoverflow.com");
}
For parsing html look at Html Agility Pack or something similar.
If this is console application you don't need to call Application.Run(), otherwise you should consider showing splash screen with progress to give user some feedback.
Usage of urls[i] in your original snippets is wrong. Search C# documentation for closures. You will need to make a local copy before using it.
Furthermore, you should swap weBrowser.Dispose() and weBrowser.Stop(). You can't stop the disposed browser anymore (if Stop is necessary at all).
Finally, don't abort the thread - it will finish itself.

Threading in C# method with parameter using same variable

I'm a newb in programming and I'm trying to do my first thingy that would be for someone else and not just me (so shouldn't be that crappy ^^ )
It's a Online-Checker for clients in LAN network (so he can just paste a list of clients, and it returns the online or offline).
fyi: I'm using Try/Catch because ping.send to an offline host returns in an Error which crashed the application.
Currently it looks like this:
private void btn_check_Click(object sender, EventArgs e)
{
string[] hosts = txt_hosts.Text.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
foreach (String host in hosts)
{
pinger(host);
}
}
public void pinger(string host)
{
var ping = new System.Net.NetworkInformation.Ping();
try
{
var result = ping.Send(host);
txt_result.Text += "true" + Environment.NewLine;
Application.DoEvents();
}
catch
{
txt_result.Text += "false"+Environment.NewLine;
Application.DoEvents();
}
}
Now, the interface is like frozen whenever a ping.send is processing (and that's quiet long cause of the timeout of pings).
Is there any way to do this threaded? Before I tried to start a thread, but that doesn't work either because both write in txt_result and that returns an error.
Thanks for any help!
If use acync/await:
// send request
foreach (string host in hosts)
pinger(host);
// async function
async void pinger(string host)
{
var ping = new System.Net.NetworkInformation.Ping();
bool bResp;
try
{
var result = await ping.SendPingAsync(host, 4000);
bResp = result.Status == System.Net.NetworkInformation.IPStatus.Success;
}
catch { bResp = false; }
txt_result.Text += bResp.ToString() + Environment.NewLine;
}
System.Threading.Tasks.Task.Factory.StartNew(() =>
{
pinger(host);
});
It could throw an exception at the line : txt_result.Text = "...";
Because you are trying to modify a value in a thread from another thread.
So you could write:
System.Windows.Threading.Dispatcher.CurrentDispatcher.Invoke(new Action(() =>
{
txt_result.Text = "...";
}));
Which will request the UI thread to modify the value.
Run on a background worker.
public void pinger(string host)
{
var bw = new BackgroundWorker();
bw.DoWork += delegate(object sender, DoWorkEventArgs e)
{
var ping = new System.Net.NetworkInformation.Ping();
try
{
var result = ping.Send(host);
e.Result = new object[] { result};
}
catch(Exception ex)
{
// Catch specific exceptions here as needed
}
};
bw.RunWorkerCompleted += (bw_txt_results);
bw.RunWorkerAsync();
}
private void bw_txt_results(object sender, RunWorkerCompletedEventArgs e)
{
txt_result = e.result[0].ToString();
}

Categories