public IDisposable subscription;
public ProcessData(DeviceModel model, string name = "") : base(model, name)
{
BaseAddress = _model.Process.oxyVal.regAddr;
CurrentSampleRate=1000;
subscription = Observable.Interval(TimeSpan.FromMilliseconds(CurrentSampleRate)).Subscribe(async t => await Refresh());
}
public async Task Refresh()
{
Status = "Fetching from device...";
if ((_model == null) || !_model.IsSerialPortOpen || busy)
{
StatusTrans = "Device not connected.";
return;
}
busy = true;
try
{
await ReadFromDevice().ConfigureAwait(false);
StatusTrans = "Completed.";
}
catch (Exception ex)
{
StatusTrans = ex.Message;
Trace.WriteLine(ex.Message);
}
busy = false;
}
protected override async Task ReadFromDevice()
{
var SampleRate_var = await _model.Measurement.sampleRate.sampleRate.GetValue();
CurrentSampleRate = SampleRate_var * 1000;
/*****other code********/
}
public void ChangeSampleRate()
{
subscription?.Dispose();
Observable.Interval(TimeSpan.FromMilliseconds(CurrentSampleRate)).Subscribe(async t => await Refresh());
}
I have been trying to fetching details from device.On the start,i'll subscribe a event 1 sec,in the it try to read from device(ReadFromDevice) and i'll change get the CurrentSampleRate,Onproperty change,that time I'll dispose 1sec subscribe event and i will subscribe new event with current sample rate.But problem is ReadFromDevice happens at every 1 sec.
Try this:
var CurrentSampleRate = 30;
Observable
.Generate(0, x => true, x => x + 1, x => x, x => TimeSpan.FromMilliseconds(CurrentSampleRate))
.Subscribe(x =>
{
if (x == 50)
{
CurrentSampleRate = 1000;
}
Console.Write(".");
});
It's a little nasty in that you're changing some external state to make the observable's interval change - so you may need to use Interlocked.Exchange to make the update safe.
Related
Ok. I know that I should not fire an Event inside a Getter, but I'm drafting code in LinqPad and Dotnetfiddle, so I want to be concise, and not create another method.
I have a loop routine that:
await Task.Run(()
=> RepeatAction.Every(() =>
{
if (!this.AllCyclesEnded || NumberOfSteps == 1)
{
if (NumberOfSteps > 1) ++Counter;
var tidalVolume = 500; var plateauPressure = SimulatePlateauAdjustment(12f, this.CurrentPEEP);
//var plateauPressure = 29;
var thisCycle = MeasurementCycle.Creator(this.CurrentPEEP, tidalVolume, plateauPressure);
if (!IsIdealPEEP)
CycleIterator(thisCycle);
}
},
TimeSpan.FromSeconds(StepDuration), cancellation.Token).Wait()
, abortedCyclesBecauseIdealPEEPFound.Token);
And depending of some things that CycleIterator(thisCycle); does, it fires some Events:
public bool AllCyclesEnded
{
get
{
if (HaveAllCyclesEnded && !CyclesEndedEventFired)
{
CyclesEndedEventFired = true;
OnCycleEnded(new CycleEndedEventArgs(Cycle.Count > 0 ? Cycle.LastOrDefault() : default
, this.Counter, this.CurrentPEEP, this.EndPEEP
, this.AllCyclesEnded, this.CyclePhase));
Console.WriteLine($"\t\tEnded # {this.Counter} loops with currentPEEP of {this.CurrentPEEP} in {this.CyclePhase} phase.");
//Without above, neither of these events fire...
OnCyclesEnded(new CyclesEndedEventArgs(Cycle.Count > 0 ? Cycle.LastOrDefault() : default
, this.Counter, this.CurrentPEEP, this.EndPEEP, this.CyclePhase));
}
return HaveAllCyclesEnded;
}
}
This piece of code above only fires IF I left the Console.WriteLine there; if not, Getter is called (AllCyclesEnded == true), but Events are not Fired...
Any hints?
EDIT2: Console.WriteLine solve the problem in a non deterministically way; about 60% of runs...
EDIT1 after Charlieface comments; it is a Task that returns an Action:
public static class RepeatAction
{
public static async Task Every(Action action,
TimeSpan interval, CancellationToken cancellationToken)
{
while (true)
{
action();
Task task = Task.Delay(interval, cancellationToken);
try
{
await task;
}
catch (TaskCanceledException)
{
return;
}
}
}
}
I have an abstract class which runs threads:
protected volatile bool HasError = false;
public void Run()
{
var readingThread = new Thread(ReadInFile);
var compressingThreads = new List<Thread>();
for (var i = 0; i < Environment.ProcessorCount; i++)
{
var j = i;
ProcessEvents[j] = new AutoResetEvent(false);
compressingThreads.Add(new Thread(() => Process(j)));
}
var writingThread = new Thread(WriteOutFile);
readingThread.Start();
foreach (var compressThread in compressingThreads)
{
compressThread.Start();
}
writingThread.Start();
WaitHandle.WaitAll(ProcessEvents);
OutputDictionary.SetCompleted();
writingThread.Join();
Console.WriteLine(!HasError ? "Successfully competed" : "Error");
}
Well, and I don't know how I can check the Exception?
This is class realizes abstract class.
This is one method :
protected override void Process(int processEventId)
{
try
{
while (InputQueue.Dequeue(out Chunk chunk) && !HasError)
{
var compressedChunk = GZip.GZip.CompressByBlocks(chunk.Bytes);
OutputDictionary.Add(chunk.Id, compressedChunk);
}
ProcessEvents[processEventId].Set();
}
catch (Exception e)
{
HasError = true;
}
}
As you can see, I change the value of a variable when I catch an exception, but will it work? I do not understand how to check.
The better answer is probably not to use Threads but use Parallel.For(), it manages your errors and also has better options to handle workload.
But in your current setup, just add a wrapper method:
var j = i;
ProcessEvents[j] = new AutoResetEvent(false);
compressingThreads.Add(new Thread(() => SafeCallProcess(j) ));
and
private void SafeCallProcess(int j)
{
try
{
Process (j);
}
catch(Exception e)
{
// deal with it
}
}
You could move the Set() to the wrapper too, up to your taste I guess.
So, i was making a discord bot that would be able to change a role's colour every after a certain amount of time. it ran properly, however, the bot is unable to register other commands or run any other work while this task is being run. (it wont stop when the stop command is run as it couldn't get in there in the first place).
i was hoping someone here could help fix this problem.
so here's part of the code:
[Group("rainbow")]
public class Rainbow : ModuleBase<SocketCommandContext>
{
public Boolean enabled;
[Command, RequireUserPermission(GuildPermission.ManageRoles)]
public async Task rainbowAsync(SocketRole role, int milliseconds)
{
if (milliseconds >= 500) {
enabled = true;
while (enabled)
{
Random rnd = new Random();
double id = rnd.NextDouble() * 7;
if (id < 1)
{
await role.ModifyAsync(a => a.Color = Discord.Color.Red);
}
else if (id < 2)
{
await role.ModifyAsync(a => a.Color = Discord.Color.Orange);
}
else if (id < 3)
{
await role.ModifyAsync(a => a.Color = Discord.Color.LightOrange);
}
else if (id < 4)
{
await role.ModifyAsync(a => a.Color = Discord.Color.Green);
}
else if (id < 5)
{
await role.ModifyAsync(a => a.Color = Discord.Color.Blue);
}
else if (id < 6)
{
await role.ModifyAsync(a => a.Color = Discord.Color.DarkBlue);
}
else if (id < 7)
{
await role.ModifyAsync(a => a.Color = Discord.Color.Purple);
}
await Task.Delay(milliseconds);
}
}
else { await ReplyAsync("Time value must be higher than 500ms"); }
}
[Command("stop"), RequireUserPermission(GuildPermission.ManageRoles)]
public async Task StopAsync()
{
enabled = false;
await ReplyAsync("Rainbow effect stopped");
}
}
As Alex mentioned in his comment,
Your command goes into an infinite loop.
if (milliseconds >= 500) {
enabled = true;
while (enabled)
{
//Code
await Task.Delay(milliseconds);
}
}
This puts your command into an infinite loop which prevents other commands from firing. The reason this prevents other commands from firing in an Async environment is because Async is still just a single thread and the default way Discord.net calls your command is await Command();
When an async call is awaited it blocks the call until the Task completes. Your task will never complete because of the infinite loop.
There are a couple different ways to handle this, but the way I would suggest to handle it is to schedule the recoloring. Look into ways to schedule tasks to happen every x time-frame.
As an example
public class TimerTask
{
private readonly Timer _taskTimer;
public TimerTask(Action action, int interval = 10000)
{
_taskTimer = new Timer { AutoReset = true, Interval = interval };
_taskTimer.Elapsed += (_, __) => action();
}
public void Start() { _taskTimer.Start(); }
public void Stop() { _taskTimer.Stop(); }
}
I have a probably simple question about the task factory. I have to following code:
In this task is a loop that is polling data from the RS232 and a counter that stops polling after 10 times. After this "doCollect" will be set to false.
And now comes the strange thing: The task runs repeatedly. The caller code is:
// class Main()
RS232DataAquisition _RS232DataAquisition = new RS232DataAquisition();
public override void Run()
{
System.Diagnostics.Stopwatch timeout = new System.Diagnostics.Stopwatch();
timeout.Start();
_RS232DataAquisition.Start();
while ((timeout.ElapsedMilliseconds <= (dataGatherTime_inSeconds * 1000)) && _RS232DataAquisition.DoCollect)
{
System.Threading.Thread.Sleep(100);
}
timeout.Stop();
_RS232DataAquisition.Stop();
}
Per my understanding the Run() function should start the thread and return into the while-loop waiting for the thread to finish. But it never does?!
Here's the code for ReadDataFromRS232:
// sealed class RS232DataAquisition
private bool doCollect = false;
public bool DoCollect
{
get { return doCollect; }
}
public void Start()
{
doCollect = true;
currentTask = System.Threading.Tasks.Task.Factory.StartNew(() =>
{
this.ReadDataFromRS232();
});
}
private void ReadDataFromRS232(int NumtoRead = 10)
{
var port = new System.IO.Ports.SerialPort(PortName);
int waitCount = 5;
var portExists = System.IO.Ports.SerialPort.GetPortNames().Any(x => x == PortName);
if (!portExists)
{
throw new ArgumentException("Port does not exist!");
}
while (port.IsOpen && waitCount-- > 0)
{
doCollect = false;
Wait();
}
doCollect = true;
if (!port.IsOpen)
{
port.Open();
port.NewLine = _NewLine;
port.ReadTimeout = 2000;
int number;
try { }
finally { }
port.Write("flashon\r");
while (doCollect && (_readCounter <= NumtoRead))
{
string s;
try
{
s = port.ReadLine();
}
catch
{
s = "-1";
}
int i;
if (int.TryParse(s, out i))
{
number = Convert.ToInt32(s, 10);
}
else
{
number = 0;
}
lock (thisLock) _data.Add(number);
_readCounter++;
}
port.Write("flashoff\r");
port.Close();
port.Dispose();
Wait(); Wait();
}
}
private void Wait()
{
System.Threading.Thread.Sleep(10);
System.Threading.Thread.SpinWait(1);
}
I don't get, why "ReadDataFromRS232" is beeing repeated until the timeout stops this task.
Thank you for any help :)
EDIT: Added some missing code.
As Dennis said the problem seemed to come from the missing volatile. It works now even though I have no idea why it didn't before.
In my application I have three asynchronous events.
After all of them are complete I need to call some Method1().
How can I implement this logic?
Update
Here is one of my asynchronous events:
public static void SetBackground(string moduleName, Grid LayoutRoot)
{
var feedsModule = FeedHandler.GetInstance().ModulesSetting.Where(type => type.ModuleType == moduleName).FirstOrDefault();
if (feedsModule != null)
{
var imageResources = feedsModule.getResources().getImageResource("Background") ??
FeedHandler.GetInstance().MainApp.getResources().getImageResource("Background");
if (imageResources != null)
{
//DownLoad Image
Action<BitmapImage> onDownloaded = bi => LayoutRoot.Background = new ImageBrush() { ImageSource = bi, Stretch = Stretch.Fill };
CacheImageFile.GetInstance().DownloadImageFromWeb(new Uri(imageResources.getValue()), onDownloaded);
}
}
}
Bit field (or 3 booleans) set by each event handler. Each event handler checks that the condition is met then calls Method1()
tryMethod1()
{
if (calledEvent1 && calledEvent2 && calledEvent3) {
Method1();
calledEvent1 = false;
calledEvent2 = false;
calledEvent3 = false;
}
}
eventHandler1() {
calledEvent1 = true;
// do stuff
tryMethod1();
}
Not given any other information, what will work is to use a counter. Just an int variable that is initialized to be 3, decremented in all handlers and checked for equality to 0 and that case go on.
You should use WaitHandles for this. Here is a quick example, but it should give you the basic idea:
List<ManualResetEvent> waitList = new List<ManualResetEvent>() { new ManualResetEvent(false), new ManualResetEvent(false) };
void asyncfunc1()
{
//do work
waitList[0].Set();
}
void asyncfunc2()
{
//do work
waitList[1].Set();
}
void waitFunc()
{
//in non-phone apps you would wait like this:
//WaitHandle.WaitAll(waitList.ToArray());
//but on the phone 'Waitall' doesn't exist so you have to write your own:
MyWaitAll(waitList.ToArray());
}
void MyWaitAll(WaitHandle[] waitHandleArray)
{
foreach (WaitHandle wh in waitHandleArray)
{
wh.WaitOne();
}
}