Threading doesn't work correctly - c#

I have an application, which is to repeat the numbers what I hear then record the digits what I read. The numbers are 0,1,2,3,4,5,6,7,8,9. I use a for loop to play these numbers with a text to speech skill, which is from a third party.
For the recording part, I have to put it in a separate thread by the third party requirement. To record the voice, the method is likely:
recordVoiceResource.Record(fileName);
To stop it, use:
recordVoiceResource.Stop();
Now I find sometimes my recording is 0 second, which means the code perhaps doesn't reach Record line. Sometimes it only has 2 seconds. I believe the thread schedule is wrong.
private ManualResetEvent terminate = new ManualResetEvent(false);
PlayTTS("Please repeat the following numbers as you hear them.");
Thread t = new Thread(() => RecordNumbers());
t.Start();
Thread.Sleep(2000);
terminate.Set();
terminate.WaitOne();
PlayNumbers();
recordVoiceResource.Stop();
The thread method is:
private void RecordNumbers()
{
recordVoiceResource = TelephonyServer.GetVoiceResource();
recordVoiceResource.MaximumSilence = 1;
recordVoiceResource.MaximumTime = 30;
// Start recording what I read from I heard
recordVoiceResource.Record(fileName);
}
To playNumbers,
private void PlayNumbers()
{
foreach (var item in numbers)
{
try
{
vr.PlayTTS(item.ToString()); // will be 0,1,2,...9
Thread.Sleep(2000);
}

According to your comment, the property MaximumSilence gets or sets the maximum silence in seconds that will be allowed until termination of the next voice function. You are setting it to one second, starting the recording, and then sleeping for two seconds before beginning playback that prompts the user to say something. Do you see the problem here? Assuming the mic doesn't pick up some unrelated speech during that period, the recording will stop before the playback even begins.
Since there is a 2-second gap between number playback, you probably need to set MaximumSilence to several seconds.
That is, of course, assuming your intention was to capture a single recording of the user speaking all the numbers (which is how your code is written). If you want to capture the spoken numbers individually, then you may need to schedule and synchronize separate recordings as each number is played back. You may want to double-check the API to make sure your solution is what you intended.

It is very likely your problem is causing due to Thread.Sleep(). Use a timer instead:
System.Timers.Timer Record = new System.Timers.Timer();
Record.Interval = 2000;
Record.Elapsed += new System.Timers.ElapsedEventHandler(Record_Elapsed);
void Record_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
Record.Enabled=false;
PlayNumbers();
recordVoiceResource.Stop();
}
And set:
Thread t = new Thread(() => RecordNumbers());
t.Start();
Record.Enabled=true;

Related

Stopping SoundPlayer from a different thread while it's playing

For the sake of making a (shuffled) playlist, I've made a separate thread in which I load and play each song in the playlist. The background stuff (wav files, file paths, playlists and shuffling) all work without a hitch.
The issue is that I have 2 windows, each of which can close and open the other. Each window has a different playlist, and when I switch to the other window, I want my static SoundPlayer to stop playing, then start playing the new playlist.
This currently isn't working: currently, the application waits until the current track is finished before displaying the next window and starting the other playlist. Yes, the entire application waits on this.
I'm new to thread coding, so I'm not really sure what to do. The two methods of stopping this I've tried so far have been SoundPlayer.Stop() and Thread.Abort(). Neither changes the situation at all.
In each window:
Thread playlistThread;
public Window()
{
InitializeComponent();
MusicPlayer.music.Stop();
playlistThread = new Thread(() => MusicPlayer.PlayPlaylist(MusicPlayer.ShufflePlaylist(MusicPlayer.PlaylistFromType("[insert track type]"), random)));
playlistThread.Start();
PlayPlaylist which I will show next takes a List of strings, so don't worry about the Thread line, it's just a few sections put into one. The properties after that simply generate that list, and again, that all works, but I can show it if anyone thinks it's necessary. Here is the PlayPlaylist method:
public static void PlayPlaylist(List<string> tracks)
{
for (int i = 0; i < tracks.Count; i++)
{
music.SoundLocation = tracks[i];
music.PlaySync();
}
}
Here's the answer I worked out:
public static void PlayTrack(List<string> tracks, int i)
{
while (true)
{
if (i == tracks.Count)
{
tracks = MusicPlayer.ShufflePlaylist(tracks, MusicPlayer.random);
i = 0;
}
music.SoundLocation = tracks[i];
int l = SoundInfo.GetSoundLength(tracks[i]);
music.Play();
while (l > 0)
{
Thread.Sleep(1000);
l -= 1000;
}
i++;
}
}
The SoundInfo class with its GetSoundLength method I found here.
The reason this method works while others do not is because of how Play() and PlaySync() work. PlaySync() plays the entire .wav file in the current thread, with nothing else running until it finishes. Thus, even SoundPlayer.Stop() and Thread.Abort() do not work, as they insert a new line after the current one.
By running this method in a new thread, you avoid PlaySync() giving you that issue. However, it will still be impossible to stop the track ahead of time using PlaySync(). This is why you use Play() instead.
Therein lies a second issue, however: Play() plays the track in its own thread, meaning the rest of the code will continue. This is a big risk if you're wanting to do anything only after the current track finishes.
The answer is to calculate the length of the track you're going to play. Then simply create a while loop, running until l (given by GetSoundLength()) reaches 0. In each pass through the loop the thread (separate from your window's main thread) sleeps for 1 second. This is fine on the CPU and means that every second extra code, such as SoundPlayer.Stop(), can be injected into the thread.

Populate items on listview after each x seconds

I have a method that detects beacons after each 30 seconds. The scenario is as follows:
The scan period of beacons is 60 seconds.
The waiting period before the next scan is 30 seconds.
The above settings have already been defined in the BeaconDectector class. Now to display the beacons scanned on my UI, I have the following:
private void Button_Clicked(object sender, EventArgs e)
{
bool start = true;
while (start) {
beaconsFound = StartDetection();
Device.BeginInvokeOnMainThread(() =>
{
listView.ItemsSource = beaconsFound;
});
}
}
The StartDetection contains the logic that take place every 30 seconds and the scan period is 60 seconds. How can I ensure that I don't miss any beacons to get displayed on my listview?
Please advise. Thank you.
You should definitely not use active waiting while(start) to manage this. A better solution would be a Timer. You can see the basics for this in this blogpost.
Furthermore, ensure you are not running any long running code on the UI thread (which is what Button_Clicked runs on). Ideally, your timer should fire each 30 seconds, start a new Task for the detection and use Device.BeginInvokeOnMainThread to update the list when appropriate.

Keeping console app from closing but still run codes

I have a console app that does not terminate using a code
new System.Threading.AutoResetEvent(false).WaitOne();
What I want to achieve: I would want to run a StopWatch and if it meets a condition it will run certain file manipulating codes. And then finally after the block of code, resets the timer and wait for it to be true again to rerun.
Problem: However, upon debugging I cant get my code to go through my conditions even it has already passed the required condition.
My Code:
static void Main(string[] args)
{
string mutex_id = "41585f436f766572743243494d";
using (System.Threading.Mutex mtx = new System.Threading.Mutex(false, mutex_id))
{
if(!mtx.WaitOne(0,false))
{
return;
}
processTimer = new Stopwatch();
processTimer.Start();
if (processTimer.Elapsed.Seconds > 10)
{
processTimer.Stop();
fileQueue = Directory.GetFiles(ConfigurationManager.AppSettings["WatchPath"], ConfigurationManager.AppSettings["Format"]).ToList();
}
//process the fileQueue
//..
//..
//processTimer.Reset(); -> Reset Timer to wait for another 10 sec and process again
new System.Threading.AutoResetEvent(false).WaitOne();
}
}
I have used a FileSystemWatcher before but I failed to get the process correctly(Like Consecutive/Concurrent file creations and such). Tried Threading and Timers as my question.
Now I'm trying to approach this issue from a new perspective. Hope some can enlighten me with this.
There is no "try again" in your code.
The code you've written does the following:
Create a mutex and lock it
If it already exists, close application
Start a stopwatch
Check if 10 seconds elapsed (which they didn't)
Create a new AutoResetEvent and wait for ever for it
You will need some loop that periodically checks if 10 seconds have passed and otherwise Sleep

How to read/write on console at the same time using threads

I want to implemente a C# Console Application that runs a simulation. Also, I want to give to the user the oportunity to acelerate/decelerate the speed of the simulation pressing '+' or '-' on console.
Is there a way to read the console while writing on it? I believe I could use multithreading for this, but I don't how to do it (I'm still new on C#).
Thank you very much!
You can check Console.KeyAvailable prior to calling Console.ReadKey(). This will let you check the console to see if there is input waiting (ie: the user pressed + or -) without blocking. If you just don't try to read if there is no input available, your main thread will never block waiting on the user.
Using this mechanism, you can actually do this in a single threaded application.
Yes, there is a way to read/write at the "same time". There are a couple of ways to do it:
Use another Thread:
First, you start a thread that is responsible for writing to the console.
Thread t = new Thread(()=>{RunSimulation();});
t.IsBackground = true;
t.Start();
The simulation method would look something along the lines of:
public void RunSimulation()
{
while(running)
{
// Puts the thread to sleep depending on the run speed
Thread.Sleep(delayTime);
Console.WriteLine("Write your output to console!");
}
}
Second, you can continually let the main thread poll for user input in order to make adjustments.
string input = string.Empty;
while(input.Equals("x", StringComparison.CurrentCultureIgnoreCase)
{
input = Console.ReadKey();
switch(input)
{
case "+":
// speeds up the simulation by decreasing the delayTime
IncreaseSpeed();
break;
case "-":
// slows down the simulation by decreasing the delayTime
DecreaseSpeed();
break;
default:
break;
}
}
Use a Timer:
Another approach is to use a [Timer][1] and adjust the frequency of callbacks on the timer instead of adjusting the sleep time on a thread:
// Create the timer
System.Timers.Timer aTimer = new System.Timers.Timer(10000);
// Hook up the Elapsed event for the timer.
aTimer.Elapsed += new ElapsedEventHandler(OnPrintSimulationResult);
// Change the Interval to change the speed of the simulation
aTimer.Interval = 2000; // <-- Allows you to control the speed of the simulation
aTimer.Enabled = true;
Of course, you have to deal with thread safety, but this should give you a decent place to start. You can come back once you try one of those approaches and you're having a specific problem with it, I'm sure people would be happy to address any particular issues you have. Note that it will not be a very graceful-looking solution to do it in the console, but it will work. If you want something more graceful, then simply make a GUI application that has a text area, redirect the console output to the text area and add 2 buttons (+/-) to adjust the speed.
[1]: http://msdn.microsoft.com/en-us/library/system.timers.timer.aspx

C# Downloader: should I use Threads, BackgroundWorker or ThreadPool?

I'm writing a downloader in C# and stopped at the following problem: what kind of method should I use to parallelize my downloads and update my GUI?
In my first attempt, I used 4 Threads and at the completion of each of them I started another one: main problem was that my cpu goes 100% at each new thread start.
Googling around, I found the existence of BackgroundWorker and ThreadPool: stating that I want to update my GUI with the progress of each link that I'm downloading, what is the best solution?
1) Creating 4 different BackgroundWorker, attaching to each ProgressChanged event a Delegate to a function in my GUI to update the progress?
2) Use ThreadPool and setting max and min number of threads to the same value?
If I choose #2, when there are no more threads in the queue, does it stop the 4 working threads? Does it suspend them? Since I have to download different lists of links (20 links each of them) and move from one to another when one is completed, does the ThreadPool start and stop threads between each list?
If I want to change the number of working threads on live and decide to use ThreadPool, changing from 10 threads to 6, does it throw and exception and stop 4 random threads?
This is the only part that is giving me an headache.
I thank each of you in advance for your answers.
I would suggest using WebClient.DownloadFileAsync for this. You can have multiple downloads going, each raising the DownloadProgressChanged event as it goes along, and DownloadFileCompleted when done.
You can control the concurrency by using a queue with a semaphore or, if you're using .NET 4.0, a BlockingCollection. For example:
// Information used in callbacks.
class DownloadArgs
{
public readonly string Url;
public readonly string Filename;
public readonly WebClient Client;
public DownloadArgs(string u, string f, WebClient c)
{
Url = u;
Filename = f;
Client = c;
}
}
const int MaxClients = 4;
// create a queue that allows the max items
BlockingCollection<WebClient> ClientQueue = new BlockingCollection<WebClient>(MaxClients);
// queue of urls to be downloaded (unbounded)
Queue<string> UrlQueue = new Queue<string>();
// create four WebClient instances and put them into the queue
for (int i = 0; i < MaxClients; ++i)
{
var cli = new WebClient();
cli.DownloadProgressChanged += DownloadProgressChanged;
cli.DownloadFileCompleted += DownloadFileCompleted;
ClientQueue.Add(cli);
}
// Fill the UrlQueue here
// Now go until the UrlQueue is empty
while (UrlQueue.Count > 0)
{
WebClient cli = ClientQueue.Take(); // blocks if there is no client available
string url = UrlQueue.Dequeue();
string fname = CreateOutputFilename(url); // or however you get the output file name
cli.DownloadFileAsync(new Uri(url), fname,
new DownloadArgs(url, fname, cli));
}
void DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
DownloadArgs args = (DownloadArgs)e.UserState;
// Do status updates for this download
}
void DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
DownloadArgs args = (DownloadArgs)e.UserState;
// do whatever UI updates
// now put this client back into the queue
ClientQueue.Add(args.Client);
}
There's no need for explicitly managing threads or going to the TPL.
I think you should look into using the Task Parallel Library, which is new in .NET 4 and is designed for solving these types of problems
Having 100% cpu load has nothing to do with the download (as your network is practically always the bottleneck). I would say you have to check your logic how you wait for the download to complete.
Can you post some code of the thread's code you start multiple times?
By creating 4 different backgroundworkers you will be creating seperate threads that will no longer interfere with your GUI. Backgroundworkers are simple to implement and from what I understand will do exactly what you need them to do.
Personally I would do this and simply allow the others to not start until the previous one is finished. (Or maybe just one, and allow it to execute one method at a time in the correct order.)
FYI - Backgroundworker

Categories