Hey so I am working on something that does the following logic.
Create Parent App, Create Child Process, Have Child process poll data, Send data to Parent App,
Everything is setup fine and is working when I manually Console.WriteLine in child process and I receive that fine in the Parent App.
The problem lies in the fact that the child process is polling input from an xbox controller and then sending that information to the parent app. The problem is that the only way I can think of keeping the child process alive is put in a while loop in Main, once a certain condition is met than close.
However the while loop isn't allowing the process to poll since its just stuck in the loop.
The main caveat is that the polling is done through events so I can't manually poll.
Any ideas on how to keep the passive event type polling to work while keeping the process open?
Here is the setup:
static Battler m_battler = new Battler();
static void Main(string[] args)
{
m_battler = new Battler();
string[] procArgs = (string[])args;
if (procArgs.Length == 0)
{
Console.WriteLine("No Args passed");
Console.Read();
return;
}
parsedArg = procArgs[0].Split('^');
m_battler.NumBattles = Convert.ToInt32(parsedArg[0]);
m_battler has the controller in it and then that uses events to call a function to parse the input and sends it to the parent app, again there is no poll loop its just something like m_xboxController.ProcessedDebugOutput += new XboxController.DebugOutputHandler(Result);
Result parses everything then sends it to the parent app
private void AddHandler()
{
Console.WriteLine("handler");
m_xboxController = new XboxController();
TestDelegate testDel = new TestDelegate(Result);
m_xboxController.ProcessedDebugOutput += new XboxController.DebugOutputHandler(testDel);
threadInit = false;
}
public void Init(int consoleNum, string activeConsole)
{
ThreadStart ts = new ThreadStart(AddHandler);
outputThread = new Thread(ts);
outputThread.Start();
while (threadInit)
{
continue;
}
}
Here is more detail on what is happening
Events are not magical. Depending on how the Battler class or the inner mechanism works, the event handler will be called:
Synchronously
Asynchronously on a separate thread
Asynchronously by invoking on the main thread
The 1st and 2nd option will work with an infinite loop (option 2 will require some thread synchronisation). It appears you believe option 3 is the case.
Before I suggest a solution, could you provide more info on exactly how the event is fired? What makes you think it's dispatched as a message to the main thread and needs to be read from message loop? What is this XboxController class you're using?
Related
I am working on wpf application where so many UI screens are available and each UI contains lots of processing using multi threading, task await, dispatcher and, background worker. So now I have two buttons START and STOP. Now when I will click START button then whole application's process(long running process) need to run in while loop. Which causing application freeze. So now I want to transfer my process in another class in another normal application. which will contains only logic and I will need to send only single parameter to that application.
Now I want to achieve like when I will click on start button from my WPF application then another application(which contains only cs file there will be not any type of UI) need to run in while loop. And again when I will click STOP button then again that application need to stop it's work. I don't know about it's logic how to implement but I have an idea like I describe. So please can you guide me little bit that how can I implement that ?
For that like I have a WPF application and second one is console application.
Now in my Console Application code is like :
public static void Main(string[] args)
{
startProcess("This is running");
}
public static void startProcess(string name)
{
StreamWriter log;
string filePath = #"D:\TimeLogFile.txt";
for (int i = 0; i <= 10; i++)
{
log = File.AppendText(filePath);
log.WriteLine(name);
log.Close();
}
}
now I need to pass string parameter from my WPF application and want to run this console application from my WPF application. So please can you guide me that how can I achive it ?
from WPF application when I will click Start button then I want to run console application with passing parameters. I have try below code which is running my console application but don't know how to pass parameter and fetch it on console application side.
using(System.Diagnostics.Process process = new System.Diagnostics.Process())
{
process.StartInfo.UseShellExecute = false;
process.StartInfo.FileName = #"D:\StockTest.exe";
process.StartInfo.CreateNoWindow = true;
process.Start();
}
it's running console application but I want to pass parameter also there. So how can I pass parameter to console application and run console application.
I can suggest you the abstract design of the class .
When you click on the start button , in the command handler from the view model or code behind you can fire the task and out your long running code inside the class .
For example:
Your command handler. Where LongRunningLogic is the class where your long running code should go .
LongRunningLogic _longRunningLogic = new LongRunningLogic();
Task LongRunningTask = Task.Factory.StartNew(() =>
{
_longRunningLogic.LongRunningTask(cts);
});
Actual method which performs long running operation :
class LongRunningLogic
{
public void LongRunningTask(CancellationTokenSource cts)
{
while (!cts.IsCancellationRequested )
{
//Long running code
}
}
}
To stop this operation on "Stop" click, you can do through CancellationTokenSource. Define a CancellationTokenSource at the class level of the view model and when user clicks on Stop, raise the CancellationTokenSource.
Ex:
CancellationTokenSource cts = new CancellationTokenSource();
On your stop command handler , raise cancellationtokensource like this .
cts.Cancel();
You may capitalize on the following idea:
public class Runner
{
private readonly MyClass _object;
private int _flag;
public Runner(Object param)
{
_object = new MyClass(param);
}
public void Start()
{
if (Interlocked.CompareExchange(ref _flag, 1, 0) == 0)
{
Task.Factory.StartNew(job);
}
}
private void job()
{
while (Interlocked.CompareExchange(ref _flag, 1, 1) == 1)
{
// do the job on _object
}
}
public void Stop()
{
Interlocked.Exchange(ref _flag, 0);
}
}
You then create a Runner instance in GUI, and call Start in your START button handler, and Stop - inside STOP handler. MyClass and param should be modified accordinally as well.
Your while loop is inside the job function, put your logic there. Then you hit STOP, it would stop on the next loop iteration, so it may take some time. Later you may implement some cancellation logic to react faster.
This the picture of the application that I am trying to run:
when I try to click outside, move it, or minimize it, the window hangs:
my code:
public void Process()
{
// using (HalconDotNet.HWindowControl HWinCtrl = new HalconDotNet.HWindowControl())
// {
using (PitFinderEngine VisionEngine = new PitFinderEngine())
{
foreach (string jpegfile in JpegFiles)
{
try
{
string[] parts1 = jpegfile.Split('\\');
string[] parts2 = parts1[parts1.Length - 1].Split('.')[0].Split('_');
string row = parts2[parts2.Length - 2].Split('R')[1];
string col = parts2[parts2.Length - 1].Split('C')[1];
Results.Add(row + " " + col, VisionEngine.action(jpegfile, "Production"));
//FormControls.ProgressBar_DoStep();
}
catch (Exception e)
{
}
}
}
}
the "Process" is called in this manner:
public static Thread StartTheThread(string LN, string TN)
{
var t = new Thread(() => RealStart(LN, TN));
t.Start();
return t;
}
private static void RealStart(string ln, string tn) {
Lots[ln].Tiles[tn].Process();
}
public static void DoWork()
{
string[] Directories = Directory.GetDirectories(LotPictureFolder);
List<Thread> ThreadList = new List<Thread>();
foreach (string lot in Directories)
{
string[] parts = lot.Split('\\');
string LotName = parts[parts.Length - 1];
foreach (string tile in Lots[LotName].Tiles.Keys)
{
if (!Lots[LotName].Tiles[tile].VicFileFound)
{
ThreadList.Add(StartTheThread(LotName, tile));
}
}
}
bool AllDone = false;
while (!AllDone)
{
AllDone = true;
foreach (Thread th in ThreadList)
{
if (th.IsAlive)
{
AllDone = false;
}
}
}
}
it seems that
VisionEngine.action(jpegfile, "Production")
takes 10ms - 20ms to run and is responsible to hanging the window, if i were to move the window; meaning, that if i were to comment it off the problem will not be there, is it possible to isolate this code, I tried using threads, but the issue still persists, i cant use tasks as the platform is .Net3.5.
The problem is that when you run longer tasks for you application it blocks the UI until the order is done. That's because your task blocks the MainThread for this order, so the UI can't respond, since it's running in the MainThread as well. Because the UI does not respond to Windows it's telling you: Hey, watchout this window does not respond to any user actions currently.
Even though your application does a lot of stuff in the background (what you assigned your application to do), but this does not matter for the user and Windows. The problem is that once you click more on your application, the blocked UI, Windows will still notice that and suggest you to close the window, because it seems like the application is stuck.
Simply use Application.DoEvents() in your long running task. This behaves as the following:
Calling this method causes the current thread to be suspended while all waiting window messages are processed.
So it pauses your currently long running task, to process the Windows messages which came from e.g. the user input, so maximizing, moving, ... the window. After that it will continue working on your long running order.
Application.DoEvents();
This implies that if e.g. your method takes 10s to complete, calling Application.DoEvents() once makes your application process user actions only one time, what does not seem like a behaviour you want. So you have to call it multiple times. Note that this can make your running method significantly slower.
You don't seem to use a ThreadList at this point anymore. Your whole process method should start a new thread. Then make sure with events you modify the ProgressBar it's progress. Once all of that code runs on a seperate thread your UI shouldn't freeze because of that anymore.
I'm developing a user interface for a program, and something very strange is happening.
I have a text view, 2 buttons and a progress bar. I redirectioned the output on the console to my text view. so wen I click the buttons I should receive output messages. in the beginning it was fine, but then I used some longer routines, I'm trying to log in into a web service and use web-requests.
my code works almost as It was supposed to work, I can log in and make my web requests just fine. but because the answers can become slow I created some output messages, and there my problem started.. My interface wont update until all the code I created on my event handler end's running. and when that code ends executing, I receive all the output messages all at once. I cant even move the window while the program is running..
I´m programing on c# for my first time, I had to use it because I need to use dll's.. and this kind of problem never happened before. I usually use Java.
It's like the code isn't running on the right order and it doesn´t make sense to me.. because I know my code is right because it runs on the console, and it runs while the program isn't responding..
I cant seem to understand this, should I make my events handling using threads?
class MainClass
{
public static void Main (string[] args)
{
Application.Init ();
UIMain win = new UIMain ();
win.ShowAll ();
Application.Run ();
}
}
public partial class UIMain : Gtk.Window
{
public UIMain () :
base (Gtk.WindowType.Toplevel)
{
System.Windows.Forms.Application.EnableVisualStyles ();
this.Build ();
Console.SetOut (new ControlWritter(this.textview1));
}
protected void OnButton2Clicked (object sender, EventArgs e)
{
if (entry1.Text.Equals(String.Empty) || entry2.Text.Equals(String.Empty)) {
Console.WriteLine("random output");
}
ConstantesSetup.autoSetup ();
button1.Sensitive = true;
if (!ConstantesSetup.var1) {
ConstantesSetup.routine6 ();
ConstantesSetup.routine5 ();
ConstantesSetup.routine4 ();
ConstantesSetup.routine3 ();
ConstantesSetup.routine2 ();
ConstantesSetup.var1 = true;
}
}
protected void OnButton1Clicked (object sender, EventArgs e)
{
switch (ConstantesSetup.erp) {
case "ERP":
eti_scp.autoSync (this);
break;
}
}
}
I'm sorry for the lack of code, but I don't even know were to start looking for the problem..
thanks for your time ;)
You are blocking the UI thread with long running synchronous operations. You need to run these long running operations asynchronously so that the button click event handler can return right away while your tasks run in the background.
There are several options for running tasks asynchronously but one simple option is using a BackgroundWorker. In your event handler you could do something like:
var worker = new BackgroundWorker();
worker.DoWork += (o, args) =>
{
//call long running processes here
};
worker.RunWorkerAsync();
The BackgroundWorker will also dispatch these operations onto the UI thread for you so you can update controls in the form inside the DoWork callback method.
I am developing a windows application for my company that runs on the server. It is a multi threaded application, and i am using Thread Pool for that.
My Application Email module consists of 3 major methods. 1st method gets new campaigns from database, second method decides to whom the campaign is going to be sent via email and third method sends it.
When I start the application, 1st method goes into Thread Pool, if there is a new campaign, 2nd method is invoked with the campaign info. But while these all are happening, first method has to check database in every three seconds if there is a new campaign or not.
I am not sure if I have to use System.Windows.Forms.Timer class for that or System.Threading.Timer??
And I am not sure how to implement it? Am I going to use Invoke Function to invoke thread outside the main UI? Could you please post an example code and suggest best practices??
Thanks a lot
Here is my code :
private void btnStart_MouseClick(object sender, MouseEventArgs e)
{
smartThreadPool = new SmartThreadPool();
workItemGroup = smartThreadPool.CreateWorkItemsGroup(1);
workItemGroup.QueueWorkItem(CheckNewCampaigns);
//smartThreadPool.QueueWorkItem(new WorkItemCallback(this.CheckNewCampaigns));
}
private object CheckNewCampaigns(object state) // 1st method
{
StringBuilder builder = new StringBuilder();
IEnumerable<Campaigns> CampaignsList = DatabaseManager.GetCampaignsList(DatabaseManager.GetNewCampaigns());
foreach (Campaigns Campaign in CampaignsList)
{
builder.AppendFormat("New Campaign Arrived($) --> {0}\r\n", DateTime.Now.ToLongTimeString());
builder.AppendFormat("CampaignID --> {0}\r\n", Campaign.CampaignID);
builder.AppendFormat("CustomerID --> {0}\r\n", Campaign.CustomerID);
builder.AppendFormat("ClientID --> {0}\r\n", Campaign.ClientID);
builder.AppendFormat("Title --> {0}\r\n", Campaign.Title);
builder.AppendFormat("Subject --> {0}\r\n", Campaign.Subject);
builder.AppendFormat("Status --> {0}\r\n", Campaign.Status);
}
Console.WriteLine(builder.ToString());
workItemGroup.QueueWorkItem(new WorkItemCallback(this.PrepareCampaignEmail), 2);
return true;
}
private object PrepareCampaignEmail(object CampaignID) // Second Method
{
int campaignID = (int)CampaignID;
IEnumerable<Campaigns> CampaignDetailsList = DatabaseManager.GetCampaignsList(DatabaseManager.GetCampaignDetails(campaignID)); // bir tane campaign gelmekte
IEnumerable<Subscribers> SubscribersList = DatabaseManager.GetCampaignSubscribersList(DatabaseManager.GetCampaignSubscribers(campaignID));
ArrayList test = new ArrayList();
DataTable dtCustomValuesForCampaign = DatabaseManager.GetCustomValuesForCampaign(campaignID);
foreach (Subscribers subscriber in SubscribersList)
{
workItemGroup.QueueWorkItem(new WorkItemCallback(this.SendEmail), subscriber.Email);
}
return true;
}
In your situation, since it's a Windows Forms application and you'll potentially want to update the UI in the timer event handler, I'd suggest using Windows.Forms.Timer.
Using Windows.Forms.Timer is pretty easy. In the design view of your form, select the Timer from the Toolbox and drop it on your form. Then, click on it to set the properties. You want to set Interval to 3000 (that's 3000 milliseconds), and Enabled to False.
On the Events tab, double-click the Tick event and the IDE will create a handler for you. You want the event handler to look something like this:
private void timer1_Tick(object sender, EventArgs e)
{
var stateObj = // create your state object here
CheckNewCampaigns(stateObj);
}
You'll need to start the timer (set Enabled to True). You can do that in your Create event handler, or you can enable it when the user hits the Start button. You can also stop it at any time by setting Enabled to False.
System.Thread.Timer and Windows.Forms.Timer act differently.
The System.Thread.Timer will run on a system thread. It has an internal thread pool, so it won't be run on one of the threads you explicitly created. Every interval, one of the threads in the Timer's pool will run the callback you initialized the object with.
The Windows.Forms.Timer will raise the Tick event on the current thread and will do so every interval, until you disable it.
I can't tell you which is more appropriate for your situation; it depends on whether you want to run the timer on the UI thread, as well as other factors.
Try this:
public void EnableTimer()
{
if (this.InvokeRequired)
this.Invoke(new Action(EnableTimer));
else
this.timer1.Enabled = true;
}
I am trying to populate a text box with some data, namely the names of several instruments a line at a time.
I have a class that will generate and return a list of instruments, I then iterate through the list and append a new line to the text box after each iteration.
Starting the Thread:
private void buttonListInstruments_Click(object sender, EventArgs e)
{
if (ins == null)
{
ins = new Thread(GetListOfInstruments);
ins.Start();
}
else if (ins != null)
{
textBoxLog.AppendText("Instruments still updating..");
}
}
Delegate to update textbox:
public delegate void UpdateLogWithInstrumentsCallback(List<Instrument> instruments);
private void UpdateInstruments(List<Instrument> instruments)
{
textBoxLog.AppendText("Listing available Instruments...\n");
foreach (var value in instruments)
{
textBoxLog.AppendText(value.ToString() + "\n");
}
textBoxLog.AppendText("End of list. \n");
ins = null;
}
Invoking the control:
private void GetListOfInstruments()
{
textBoxLog.Invoke(new UpdateLogWithInstrumentsCallback(this.UpdateInstruments),
new object[] { midiInstance.GetInstruments() });
}
Note: GetInstruments() returns a List of type Instrument.
I am implementing therads to try to keep the GUI functional whilst the text box updates.
For some reason the other UI controls on the WinForm such as a seperate combo box remain inactive when pressed until the text box has finished updating.
Am I using threads correctly?
Thanks.
You haven't accomplished anything, the UpdateInstruments() method still runs on the UI thread, just like it did before. Not so sure why you see such a long delay, that must be a large number of instruments. You can possibly make it is less slow by first appending all of them into a StringBuilder, then append its ToString() value to the TextBox. That cuts out the fairly expensive Windows call.
I would recommend using a SynchronizationContext in general:
From the UI thread, e.g. initialization:
// make sure a SC is created automatically
Forms.WindowsFormsSynchronizationContext.AutoInstall = true;
// a control needs to exist prior to getting the SC for WinForms
// (any control will do)
var syncControl = new Forms.Control();
syncControl.CreateControl();
SyncrhonizationContext winformsContext = System.Threading.SynchronizationContext.Current;
Later on, from any thread wishing to post to the above SC:
// later on -- no need to worry about Invoke/BeginInvoke! Whoo!
// Post will run async and will guarantee a post to the UI message queue
// that is, this returns immediately
// it is OKAY to call this from the UI thread or a non-UI thread
winformsContext.Post(((state) => ..., someState);
As others have pointed out, either make the UI update action quicker (this is the better method!!!) or separate it into multiple actions posted to the UI queue (if you post into the queue then other message in the queue won't be blocked). Here is an example of "chunking" the operations into little bit of time until it's all done -- it assumes UpdateStuff is called after the data is collected and not necessarily suitable when the collection itself takes noticeable time. This doesn't take "stopping" into account and is sort of messy as it uses a closure instead of passing the state. Anyway, enjoy.
void UpdateStuff (List<string> _stuff) {
var stuff = new Queue<string>(_stuff); // make copy
SendOrPostCallback fn = null; // silly so we can access in closure
fn = (_state) => {
// this is in UI thread
Stopwatch s = new Stopwatch();
s.Start();
while (s.ElapsedMilliseconds < 20 && stuff.Count > 0) {
var item = stuff.Dequeue();
// do stuff with item
}
if (stuff.Count > 0) {
// have more stuff. we may have run out of our "time-slice"
winformsContext.Post(fn, null);
}
};
winformsContext.Post(fn, null);
}
Happy coding.
Change this line:
textBoxLog.Invoke(new UpdateLogWithInstrumentsCallback(this.UpdateInstruments),
new object[] { midiInstance.GetInstruments() });
with this:
textBoxLog.BeginInvoke(new UpdateLogWithInstrumentsCallback(this.UpdateInstruments),
new object[] { midiInstance.GetInstruments() });
You are feeding all instruments into the textbox at once rather then one-by-one in terms of threading. The call to Invoke shall be placed in the for-loop and not to surround it.
nope, you start a thread, and then use invoke, which basically means you are going back to the UI thread to do the work... so your thread does nothing!
You might find that it's more efficient to build a string first and append to the textbox in one chunk, instead of line-by-line. The string concatenation operation could then be done on the helper thread as well.