I am learning threading in C#, and I have a problem :
I have a list of items, and each item refreshes the value of one variable every second, thanks to a DispatcherTimer.
Then, I created a thread, with an infinite loop, and send this value.
Maybe the code will be better to understand.
Product :
public class Product : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void notifyPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
private double price;
public double Price
{
get { return price; }
set
{
price = value;
notifyPropertyChanged("Price");
}
}
private Timer timer;
public Product(int time)
{
timer = new Timer(time);
timer.Elapsed += timer_Elapsed;
timer.Start();
}
void timer_Elapsed(object sender, ElapsedEventArgs e)
{
Random r = new Random();
this.Price = Math.Round(r.NextDouble() * (maxPrice - minPrice) + minPrice, 2);
}
}
Main :
public MainWindow()
{
Thread thread;
InitializeComponent();
this.DataContext = this;
thread = new Thread(() => createServer(listGroupProduct));
thread.Start();
}
public static void createServer(ObservableCollection<GroupProducts> list)
{
string client = "";
try
{
IPAddress ipAdress = IPAddress.Parse("xxx.xxx.xx.xx");
TcpListener listener = new TcpListener(ipAdress, 1220);
listener.Start();
socket = listener.AcceptSocket();
while (true)
{
articlesString = list[0].Price.ToString();
byte[] bytes = new byte[list.Count * 50];
bytes = System.Text.Encoding.ASCII.GetBytes(articlesString.ToCharArray());
socket.Send(bytes);
}
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
}
My problem is : the value send is always the same, but if I check the value in the main, the value changed...
Have you a solution ?
Declare private double price; as private volatile double price; since it's used by multiple threads.
You might want to read: http://www.andrewdenhertog.com/c/thread-safe-lock-volatile-and-interlock-in-c/
Related
I'm new to c# and currently working on a program. it has a simple UI, there are two buttons (one is called on and other one is off) and also a textbox to show some result. basically what I want to do is that if the user click "on" button, on a different class than the windows form random numbers will be generated every one second using a method. and by Implementing INotifyPropertyChanged I want to let the Textbox know that the value was updated so textbox keeps getting updated with our new random number. and once user click "off" button I want to stop generating random number.
My windows Form
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;
namespace SWE_Assignment
{
public partial class Monitor : Form
{
Patient newPatient = Patient.Instance;
public static bool pulseRateOn = false;
public Monitor()
{
InitializeComponent();
newPatient.PropertyChanged += _PulseRate_PropertyChanged;
}
private void Save_Click(object sender, EventArgs e)
{
// newPatient.PL(newPatient.startRnd = true;);
}
void _PulseRate_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "PulseRate")
{
HeartBeat.Text = newPatient.PulseRate.ToString();
}
}
private void Stop_Click(object sender, EventArgs e)
{
newPatient.startRnd = false;
}
}
}
My Patient Class
namespace SWE_Assignment
{
class Patient : INotifyPropertyChanged
{
private int _pulseRate;
public bool startRnd = false;
Random rnd = new Random();
public int PulseRate
{
get { return _pulseRate; }
set
{
_pulseRate = value;
OnPropertyChanged("PL");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string properyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(properyName));
}
private static Patient _instance = null;
private static readonly object _padlock = new object();
public static Patient Instance
{
get
{
lock (_padlock)
{
if (_instance == null)
{
_instance = new Patient();
}
return _instance;
}
}
}
public void PL(bool srt)
{
Timer timer = new Timer();
timer.AutoReset = true;
timer.Interval = 1000;
if (startRnd == true)
{
timer.Elapsed += PLS;
timer.Enabled = true;
timer.Start();
} else
{
timer.Enabled = false;
timer.Stop();
}
}
private void PLS(object sender, ElapsedEventArgs e)
{
PulseRate = rnd.Next(100, 150);
Console.WriteLine(PulseRate);
}
}
}
Also my I am using singleton pattern for my patient because I want to only have on instance of patient so that I can have access to the same random number on another class (called Alarm) to check if its bigger or smaller than a certain numbers. I do realise that is wrong with my "Stop" button as it only calls the method again and it doesn't stop method from running. I appreciate if anyone can help.
there are a few things which need to be changed.
OnPropertyChanged("PL"); - the name of property is PulseRate. "PulseRate" is what you check in event handler. make it OnPropertyChanged("PulseRate");
Timer timer = new Timer(); - you should create only one instance of Timer per Patient. better do it in constructor. otherwise you will have multiple running copies of Timer
managing Timer can be done via Enabled property:
Calling the Start() method is the same as setting Enabled to true. Likewise, calling the Stop() method is the same as setting Enabled to false.
private void Stop_Click(object sender, EventArgs e)
{
// newPatient.startRnd = false;
newPatient.PL(false);
}
class Patient : INotifyPropertyChanged
{
Timer timer;
private Patient()
{
timer = new Timer();
timer.AutoReset = true;
timer.Interval = 1000;
timer.Elapsed += PLS;
}
Random rnd = new Random();
private int _pulseRate;
public int PulseRate
{
get { return _pulseRate; }
set
{
_pulseRate = value;
OnPropertyChanged("PulseRate");
}
}
public void PL(bool srt)
{
timer.Enabled = srt;
}
private void PLS(object sender, ElapsedEventArgs e)
{
PulseRate = rnd.Next(100, 150);
Console.WriteLine(PulseRate);
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string properyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(properyName));
}
private static Patient _instance = null;
private static readonly object _padlock = new object();
public static Patient Instance
{
get
{
lock (_padlock)
{
if (_instance == null)
{
_instance = new Patient();
}
return _instance;
}
}
}
}
I'm having trouble figuring out what is wrong with my C# code.
I'm trying to learn how to use ConcurrentQueue class in System.Collections.Concurrent namespace.
In order to do this, I'm creating 2 instances of the same class in different threads, passing to the constructors a different Listbox control.
I am expecting each class instance of EventGenerator to raise events at random intervals, updating the Listbox the were passed with randomly generated number, and adding that number to a ConcurrentQueue which is also passed to the constructor.
In my main thread, is the method to DeQueue the ConcurrentQueue of objects EnQueued to it by both spawned threads.
But what I'm getting is the 2 EnQueue Listboxes displaying the same data and the DeQueue Listbox seeming reporting to have deQueued them both.
I apologize if my description is not good enough, and my code follows, along with a link to an image of my form in case it might better help visualize what I'm trying to do...
Form
public partial class Form1 : Form
{
ConcurrentQueue<int> CQ;
EventGenerator eventGenerator1;
EventGenerator eventGenerator2;
public Form1()
{
InitializeComponent();
CQ = new ConcurrentQueue<int>();
eventGenerator1 = new EventGenerator(CQ, listBox1);
eventGenerator1.OnRandomEvent += new EventGenerator.RandomEventHandler(RandomEvent);
eventGenerator2 = new EventGenerator(CQ, listBox2);
eventGenerator2.OnRandomEvent += new EventGenerator.RandomEventHandler(RandomEvent);
}
private void RandomEvent(object sender, IncomingConnectionEventArgs e)
{
string s = e.Property_Int.ToString()
+ " "
+ e.Property_String;
UpdateListbox(s, e.LB);
}
private void UpdateListbox(string argstring, ListBox argListBox)
{
if (InvokeRequired)
{
Invoke(new Action<string, ListBox>(UpdateListbox), new object[] { argstring, argListBox });
return;
}
int n;
bool b = false;
//do
//{
b = CQ.TryDequeue(out n);
//} while (!b);
argListBox.Items.Add(argstring);
argListBox.SelectedIndex = argListBox.Items.Count -1;
listBoxDeQueue.Items.Add(n.ToString());
listBoxDeQueue.SelectedIndex = listBoxDeQueue.Items.Count - 1;
}
private void button_Start_Click(object sender, EventArgs e)
{
Thread methodThread1 = new Thread(new ThreadStart(TheThread1));
methodThread1.Start();
Thread methodThread2 = new Thread(new ThreadStart(TheThread2));
methodThread2.Start();
}
private void TheThread2()
{
eventGenerator2.Start();
}
private void TheThread1()
{
eventGenerator1.Start();
}
private void button_Stop_Click(object sender, EventArgs e)
{
eventGenerator1.Stop();
eventGenerator2.Stop();
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
eventGenerator1.Stop();
eventGenerator2.Stop();
}
}
IncomingConnectionEventArgs
class IncomingConnectionEventArgs : EventArgs
{
public System.Windows.Forms.ListBox LB;
public int Property_Int { get; set; }
public string Property_String { get; set; }
public IncomingConnectionEventArgs(int argInt, string argString,
System.Windows.Forms.ListBox lb)
{
LB = lb;
Property_Int = argInt;
Property_String = argString;
}
}
EventGenerator
class EventGenerator
{
public delegate void RandomEventHandler(
object sender,
IncomingConnectionEventArgs e);
public event RandomEventHandler OnRandomEvent;
public Random r = new Random();
public ListBox listBox;
public bool Generate = true;
public ConcurrentQueue<int> CQ;
public EventGenerator(ConcurrentQueue<int> argCQ, ListBox argListBox)
{
CQ = argCQ;
listBox = argListBox;
}
public void Start()
{
Generate = true;
while (Generate)
{
Thread.Sleep(r.Next(100, 2000));
RandomEvent();
}
}
public void Stop()
{
Generate = false; ;
}
public void RandomEvent()
{
if (OnRandomEvent == null)
{
return;
}
int n = r.Next(1000, 10000);
CQ.Enqueue(n);
IncomingConnectionEventArgs Args =
new IncomingConnectionEventArgs(n, "", listBox);
OnRandomEvent(this, Args);
}
}
The problem is with your use of Random. Unless you use a single instance of Random or explicitly seed each instance differently, the two threads calling Random.Next(...) will typically generate the same values.
A better way to seed your instance is this:
Random r = new Random(Guid.NewGuid().GetHashCode());
I am trying to create an event that executes a function when a certain amount of time has changed. The timer is done by another code, it's supposed to call Plus(1), but will that change all timers (if I create multiple)? And this code is not actually working.
namespace #event
{
class Program
{
static void Main(string[] args)
{
Tick tijd = new Tick();
tijd.interval = 10;
tijd.TijdVeranderd += new EventHandler(Uitvoeren);
dynamic func = new Tick();
for (int i = 0; i < 100; i++)
{
func.Plus(1);
}
Console.ReadLine();
}
static void Uitvoeren(object sender, EventArgs e)
{
Console.WriteLine("Uitgevoerd!");
}
}
public class Tick
{
public event EventHandler TijdVeranderd;
public int interval;
private int tijd;
public void Plus(int i)
{
tijd += 1;
}
public int Verander
{
get { return this.tijd; }
set
{
this.tijd = value;
if (tijd == interval)
{
if (this.TijdVeranderd != null)
this.TijdVeranderd(this, new EventArgs());
tijd = 0;
}
}
}
public Tick() { }
}
}
EDIT: I don't want to use the .net timer, I want to create my own.
Just use .net timer like this:
System.Timers.Timer aTimer = new System.Timers.Timer();
aTimer.Elapsed += new System.Timers.ElapsedEventHandler(aTimer_Elapsed);
aTimer.Interval = 1000; //here you can set your interval
aTimer.Start();
Here you can catch the event and call other method:
void aTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
//TODO: call your method like "Plus"
}
There seem to be a couple of errors in your code:
First of all, in Main, you are calling Plus() on a different instance of Tick than the one that you configured. Try using tijd.Plus(1) instead of func.Plus(1).
Also, in the implementation of Plus, when you increment the private variable tijd, the code associated with the property Verander does not get executed, so no events ever fire. To quickly fix, increment Verander instead of tijd.
namespace #event
{
class Program
{
static void Main(string[] args)
{
Tick tijd = new Tick();
tijd.interval = 10;
tijd.TijdVeranderd += new EventHandler(Uitvoeren);
for (int i = 0; i < 100; i++)
{
tijd.Plus(1);
}
Console.ReadLine();
}
static void Uitvoeren(object sender, EventArgs e)
{
Console.WriteLine("Uitgevoerd!");
}
}
public class Tick
{
public event EventHandler TijdVeranderd;
public int interval;
private int tijd;
public void Plus(int i)
{
Verander += 1;
}
public int Verander
{
get { return this.tijd; }
set
{
this.tijd = value;
if (tijd == interval)
{
if (this.TijdVeranderd != null)
this.TijdVeranderd(this, new EventArgs());
tijd = 0;
}
}
}
public Tick() { }
}
}
You can try with this code
private static System.Timers.Timer aTimer;
public static void Main()
{
// 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 2 seconds (2000 milliseconds).
aTimer.Interval = 2000;
aTimer.Enabled = true;
Console.WriteLine("Press the Enter key to exit the program.");
Console.ReadLine();
// 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);
}
// Specify what you want to happen when the Elapsed event is
// raised.
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
Console.WriteLine("The Elapsed event was raised at {0}", e.SignalTime);
}
I don't know why you wouldn't use a system timer, but here's an [untested] implementation of a timer that should do the trick:
class MyCrudeTimer : IDisposable
{
public event EventHandler Alarm ;
public TimeSpan Duration { get ; private set ; }
public bool AutomaticallyReset { get ; private set ; }
public bool IsRunning { get ; private set ; }
private Thread timerThread ;
private ManualResetEvent start ;
private void TimerCore()
{
try
{
while ( start.WaitOne() )
{
System.Threading.Thread.Sleep( Duration ) ;
Alarm( this , new EventArgs() ) ;
}
}
catch ( ThreadAbortException )
{
}
catch ( ThreadInterruptedException )
{
}
return ;
}
public MyCrudeTimer( TimeSpan duration , bool autoReset )
{
if ( duration <= TimeSpan.Zero ) throw new ArgumentOutOfRangeException("duration must be positive","duration") ;
this.Duration = duration ;
this.AutomaticallyReset = autoReset ;
this.start = new ManualResetEvent(false) ;
this.timerThread = new Thread( TimerCore ) ;
this.timerThread.Start() ;
return ;
}
public void Start()
{
if ( IsRunning ) throw new InvalidOperationException() ;
IsRunning = true ;
start.Set() ;
return ;
}
public void Stop()
{
if ( !IsRunning ) throw new InvalidOperationException() ;
IsRunning = false ;
start.Reset() ;
return ;
}
public void Dispose()
{
try
{
if ( this.timerThread != null )
{
this.timerThread.Abort() ;
this.timerThread = null ;
}
}
catch
{
}
return ;
}
}
Per a client's request I have written a communication class that inherits from webclient. They want to be able to "Pass in a custom windows form as a progress bar" rather than that I created an interface that implements 3 properties. Anyway the problem I am having is the app starts and i click the start button so to speak and the first time i do this the ui thread is frozen, after a few seconds it unfreezes and the progress bar and data begin coming down.
After this initial freeze though , any subsequent presses of the start button work perfectly and do not block the thread any ideas?
Here are the relevant pieces of code from form 1
private void btnSubmit_Click(object sender, EventArgs e)
{
txtResponse.Text = "";
progressForm = new ProgressFormTest();
myCommunication = new CommunicationClient(progressForm);
myCommunication.DownloadStringCompleted += new DownloadStringCompletedEventHandler(wc_RequestComplete);
// myCommunication.DownloadProgressChanged += new DownloadProgressChangedEventHandler(wc_DownloadProgressChanged);
myCommunication.Timeout += new EventHandler(wc_TimeOut);
myCommunication.Cancelled += new EventHandler(myCommunication_Cancelled);
progressForm.Show();
myCommunication.TimeoutValue = (int)numConnectionTimeout.Value * 1000;
myCommunication.DownloadStringAsync(new Uri(txtUrl.Text));
}
Here is the communication class
public class CommunicationClient:WebClient
{
private int step = 1000;
private long bytesReceived;
private long bytesSent;
private Status status;
private System.Timers.Timer _timer;
private IProgress myProgressForm;
/// <summary>
/// Sets the timeout value in milliseconds
/// </summary>
public int TimeoutValue { get; set; }
public int TimeElapsed { get; set; }
public long BytesReceived
{
get
{
return bytesReceived;
}
}
public long BytesSent
{
get
{
return bytesSent;
}
}
public event EventHandler Timeout;
public event EventHandler Cancelled;
public CommunicationClient(IProgress progressForm)
{
myProgressForm = progressForm;
_timer = new System.Timers.Timer(step);
_timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
}
protected override void OnDownloadStringCompleted(DownloadStringCompletedEventArgs e)
{
_timer.Stop();
if (status == Status.Completed)
{
myProgressForm.PercentComplete = 100;
base.OnDownloadStringCompleted(e);
}
}
protected override void OnDownloadProgressChanged(DownloadProgressChangedEventArgs e)
{
bytesReceived = e.BytesReceived;
myProgressForm.BytesReceived = bytesReceived;
if (e.TotalBytesToReceive == -1)
myProgressForm.PercentComplete = calculateFakePercentage();
else
myProgressForm.PercentComplete = e.ProgressPercentage;
base.OnDownloadProgressChanged(e);
}
protected virtual void OnTimeout(EventArgs e)
{
if (Timeout != null)
{
CancelAsync();
this.Dispose();
Timeout(this, e);
}
}
protected virtual void OnCancelled(EventArgs e)
{
if (Cancelled != null)
{
this.Dispose();
Cancelled(this, e);
}
}
/// <summary>
/// Cancels a pending asynchronous operation and raises the Cancelled Event
/// </summary>
/// <param name="Event">Set to true to raise the event</param>
public void CancelAsync(bool Event)
{
CancelAsync();
if (Event)
{
status = Status.Cancelled;
OnCancelled(new EventArgs());
}
}
private void initialize()
{
status = Status.Completed;
TimeElapsed = 0;
_timer.Start();
}
new public void DownloadStringAsync(Uri url)
{
initialize();
base.DownloadStringAsync(url);
}
private void timer_Elapsed(object sender, ElapsedEventArgs e)
{
TimeElapsed += step;
if (TimeElapsed >= TimeoutValue)
{
_timer.Stop();
status = Status.Timeout;
OnTimeout(e);
}
}
//used when the website in question doesnt provide the content length
private int calculateFakePercentage()
{
return (int)bytesReceived * 100 / 60000 ;
}
}
And here is the simple Interface IProgressForm
public interface IProgress
{
int PercentComplete
{
get;
set;
}
long BytesReceived
{
get;
set;
}
long BytesSent
{
get;
set;
}
}
Fixed it , I set the Proxy property from the webclient class to null and that seemed to fix it
I'm totally new to Events and delegates in C#.
I want to handle a data read event in one class (ex. program) and port reading is done in another class(ex. transfer).
I know how to do it with delegates alone,but don't know how to do it in events.
Could you give me a simple sample. Thanks.
look at this example
public class TimerManager : INotifyPropertyChanged
{
private readonly DispatcherTimer dispatcherTimer;
private TimeSpan durationTimeSpan;
private string durationTime = "00:00:00";
private DateTime startTime;
private bool isStopped = true;
readonly TimeSpan timeInterval = new TimeSpan(0, 0, 1);
public event EventHandler Stopped;
public TimerManager()
{
durationTimeSpan = new TimeSpan(0, 0, 0);
durationTime = durationTimeSpan.ToString();
dispatcherTimer = new DispatcherTimer();
dispatcherTimer.Tick += DispatcherTimerTick;
dispatcherTimer.Interval = timeInterval;
dispatcherTimer.IsEnabled = false;
DefaultStopTime = new TimeSpan(17, 30, 0);
}
public TimerManager(TimeSpan defaultStopTime)
: this()
{
DefaultStopTime = defaultStopTime;
}
#region Properties
public TimeSpan ElapsedTime
{
get { return durationTimeSpan; }
}
public string DurationTime
{
get { return durationTime; }
set
{
durationTime = value;
OnPropertyChanged("DurationTime");
}
}
public DateTime StartTime
{
get { return startTime; }
}
public bool IsTimerStopped
{
get
{
return isStopped;
}
set
{
isStopped = value;
OnPropertyChanged("IsTimerStopped");
}
}
public TimeSpan DefaultStopTime { get; set; }
#endregion
#region Start Stop Timer
public void StartTimer()
{
dispatcherTimer.Start();
durationTimeSpan = new TimeSpan(0,0,0);
startTime = DateTime.Now;
IsTimerStopped = false;
}
public void StopTimer()
{
dispatcherTimer.Stop();
IsTimerStopped = true;
if (Stopped != null)
{
Stopped(this, new EventArgs());
}
}
#endregion
public void DispatcherTimerTick(object sender, EventArgs e)
{
// durationTimeSpan = DateTime.Now - startTime;
durationTimeSpan = durationTimeSpan.Add(timeInterval);
DurationTime = string.Format("{0:d2}:{1:d2}:{2:d2}", durationTimeSpan.Hours, durationTimeSpan.Minutes,
durationTimeSpan.Seconds);
if (DateTime.Now.TimeOfDay >= DefaultStopTime)
{
StopTimer();
}
}
}
in this class we have the Timer Stopped event
public event EventHandler Stopped;
in the Method we call the event handler if it is not null
public void StopTimer()
{
dispatcherTimer.Stop();
IsTimerStopped = true;
if (Stopped != null)
{
//call event handler
Stopped(this, new EventArgs());
}
}
for use this class and timer stop event look at the code
var timer = new TimerManager();
timer.Stopped += TimerStopped;
void TimerStopped(object sender, EventArgs e)
{
// do you code
}
If I nright understood what you're asking for, you can do something like this:
public class MyClass
{
...
public void delegate MuCustomeEventDelegate( ...params...);
public event MuCustomeEventDelegate MuCustomeEvent;
...
}