I am trying to add some elements to a dictionary in C# but I've been running into some problems. I am new to C# development so I hope someone could help me with this.
The code for adding the element is:
if (!connections.ContainsKey(port.getParentName()))
{
connections.Add(port.getParentName(), port.getLabel() + ";" + cable + ";" + cableTemplate + "|");
}
else
{
connections[port.getParentName()] += port.getLabel() + ";" + cable + ";" + cableTemplate + "|";
}
Although I'm checking if the key is allready contained in my ports dictionary I'm getting:
“An item with the same key has already been added”
Have to mention also that I am getting the data asynchronously so I would guess that this is a synchronization issue. I tried to handle this by locking this block of code but this does not seem to solve the problem:
System.Object lockThis = new System.Object();
lock (lockThis)
{
....
}
Also have to mention that I am not getting this error all the time. Just that occasionally when starting the application. Any idea what could be causing this? Is the way I'm making the synchronization wrong or is it something else?
Your lock is invalid. You need to have one instance to lock on. You currently create a new one everytime.
Use a ConcurrentDictionary<TKey, TValue> instead and use AddOrUpdate. This removes the need for a lock altogether:
var value = port.getLabel() + ";" + cable + ";" + cableTemplate + "|";
connections.AddOrUpdate(port.getParentName(), value, (k, v) => v + value);
Move your synchronization object in the scope of the class:
public class Test
{
private object syncRoot = new object();
private void Foo()
{
lock (this.syncRoot)
{
....
}
}
}
Make it static or not, depending on how you use your class.
ConcurrentDictionary can handle the synchronization issues for you.
Related
My code is passing the wrong argument to a function for some reason.
I have a static class say class A having this function AddMaster :
public static void AddMaster(string ipAddress, int port, List<RegisterMap> registers)
{
// THIS LINE PRINTS THE ACTUAL VALUES SENT FROM THE CALLER FUNCTION
System.IO.File.AppendAllText("datalog_MB.txt", ipAddress + " " + registers[0].FriendlyName + "\n");
new Thread(() =>
{
_tasks.Add(Task.Factory.StartNew(() =>
{
Monitor.Enter(_masters);
_masters.Add(new Master().Connect(ipAddress, port).SetRegisters(registers));
_masters.Last().OnEvent += MasterEvent;
Debug.WriteLine(_masters.Count + " TCP masters connected");
Monitor.Exit(_masters);
}));
}).Start();
}
I have another non-static class Master having the function SetRegisters:
public Master SetRegisters(List<RegisterMap> registerList)
{
// HERE THE FriendlyName ALWAYS PRINTS THE VALUE OF THE LAST FUNCTION CALL
System.IO.File.AppendAllText("datalog_MB_1.txt", _hostname + " " + registerList[0].FriendlyName + "\n");
_registersToRead = registerList;
return this;
}
The function AddMaster() is called in a loop.
The first code logs the following which is correct:
# datalog_MB.txt
192.168.0.12 192.168.0.12:Value 1
192.168.0.11 192.168.0.11:Value 1
However the second code block prints the following ( See the second value has changed ):
# datalog_MB_1.txt
192.168.0.12 192.168.0.11:Value 1
192.168.0.11 192.168.0.11:Value 1
Edit #1
foreach (var equipment in MSSQL.GetEquipments(true))
{
registers.Clear();
System.IO.File.AppendAllText("dataeq.txt", equipment.IPAddress + " " + equipment.Name + " " + equipment.ID + "\n");
try
{
registers.Add(
new RegisterMap
{
FriendlyName = equipment.IPAddress + ":Value 1",
Register = 2001,
Type = RegisterType.HoldingRegister,
StationID = 1
});
registers.Add(
new RegisterMap
{
FriendlyName = equipment.IPAddress + ":Value 2",
Register = 2002,
Type = RegisterType.HoldingRegister,
StationID = 1
});
A.AddMaster(equipment.IPAddress, 502, registers);
var json = new JavaScriptSerializer().Serialize(registers);
System.IO.File.AppendAllText("data_reg.txt", json + "\n\n");
}
catch(Exception err)
{
System.Windows.MessageBox.Show(err.Message);
}
}
Edit #2*
Fiddle: https://dotnetfiddle.net/h3yn7p
Any idea what might be going wrong?
You should not Clear the registers - recreate it:
List<RegisterMap> registers = null;
foreach(var equipment in equipments)
{
registers = new List<RegisterMap>();
....
}
Otherwise you are processing the same instance of List<RegisterMap> in parallel in multiple threads while manipulating it (i.e. thread which has the foreach(var equipment in equipments) loop will run and create all the threads and start them), which can lead to a lot of different concurrency issues.
Also some notes:
Consider using concurrent collections, for example ConcurrentBag<T> instead of Monitor + List (cause in current code it makes Thread/Task handling pointless)
Based on the provided code there is no need to create Thread - tasks should be enough. In modern .NET there is rarely a case when you need to create Threads manually, most of the time it is hugely discouraged (read more).
I'm using the ZedGraph library, but on a website rather than Web Forms application. Quick intro - the app gets data from a database, generates a graph, saves it as an image and then displays the image on a web page.
I have a GraphController class, which basically looks like this:
public class GraphController {
private static GraphController instance;
private static ZedGraph.ZedGraphControl graph;
protected GraphController() { }
public static GraphController Instance {
get {
if (instance == null){
instance = new GraphController();
}
return instance;
}
}
public string GenerateGraph(Dictionary<DateTime, float> graphData, DataRow details, string graphType) {
if ((graph == null) || (graph.IsDisposed == false)) {
graph = new ZedGraph.ZedGraphControl();
}
graph.GraphPane.Title.IsVisible = false;
// function calls to generate graph. Graph object is referenced in these.
return SaveGraphAsImage(0000, graphType);
}
private void AddGridLines() {
// example of graph reference
graph.GraphPane.XAxis.MajorGrid.IsVisible = true;
}
private string SaveGraphAsImage(string paramId, string graphType) {
// Should deal with save location here
string location = HttpRuntime.AppDomainAppPath + "Graphs\\" + DateTime.Now.ToString("dd-MM-yyyy");
string filename = DateTime.Now.ToString("dd-MM-yyyy-HH-mm-ss-") + graphType + "-" + paramId + ".png";
if(System.IO.Directory.Exists(location) == false){
System.IO.Directory.CreateDirectory(location);
}
graph.Refresh();
try {
using (graph) {
string outputFileName = location + "\\" + filename;
if (File.Exists(outputFileName) == false) {
Bitmap image = graph.GraphPane.GetImage(960, 660, 180);
image.Save(outputFileName, ImageFormat.Png);
image.Dispose();
}
}
graph = null; // double check that it is removed.
return "../Graphs/" + DateTime.Now.ToString("dd-MM-yyyy") + "/" + filename;
}
catch (Exception ex) {
log("An error occured generating a graph. \n\n Error message: \n " + ex.Message + " \n\n Stack trace: \n " + ex.StackTrace);
graph = null;
return "#";
}
}
}
I've reduced it as much as possible, but it should show how the ZedGraph object is created, used and removed.
I've already tried some memory enhancements, getting rid of the graph object where possible, and trying the using(){} process to hopefully automatically remove it, but would welcome further suggestions.
My aim here is to improve memory management and reduce these errors. Running local performance tests, I get quite a few Control 'ZedGraphControl' accessed from a thread other than the thread it was created on. errors. I'm relatively new to threading, so I'm not sure if a) it is something that is needed here, or b) there's something that can be done to disable the possibility, or a better management of the graph object to ensure it is always within the same thread?
Edit: This GraphController is first called from an .aspx.cs page with the following: GraphController.GraphController.Instance.GenerateGraph(data, details, "graph-type");
Second Edit: I have re-written the code to not have the ZedGraphControl as private static, but instead it is created within the GenerateGraph and then passed around where necessary. Testing this up to 1,000 users in 60 seconds looks to have removed the cross-thread issues - does this sound likely?
The issue here was the use of static variables. As pointed out by Henk Holterman in the comments, static variables stay alive as long as the application process is alive, and is separate from any/all user requests. So by having the ZedGraph object as a static variable it mean't that it was potentially still available to multiple requests without being cleared properly, running into memory and cross-threading issues.
The solution is to declare the ZedGraph instance within the first GenerateGraph function and to then pass the same object to each other function that used it. This ensures that it is the same object in the same thread that is accessed throughout the process.
Hello I've built a simple packet skeleton where each packet is a class file which extends a interface but whatever that's not important just a little intro to show you how it works and what i'm attempting to do.
say it's something like this
public static void HandlePacket(Player player, Packet p)
{
PacketHandler handler = null;
if(handlers.TryGetValue(p.getId(), out handler)) {
handler.handlePacket(player, p);
} else {
Console.WriteLine("Unhandled packet: " + p + ".");
}
}
But okay the code above is a bit unrelated to this question.. my question has to do with filling up the handlers in the most efficient way.
handlers pretty much is just
private static Dictionary<int, PacketHandler> handlers = new Dictionary<int, PacketHandler>();
Now I cannot decide which way to populate the handlers map.
First way which is ugly goes something like this.
PacketHandler temp;
temp = new TalkPacket();
handlers.Add(33, temp);
handlers.Add(66, temp);
handlers.Add(22, temp);
handlers.Add(11, temp);
the elegant way looks like this.
handlers.Add(33, new TalkPacket());
handlers.Add(66, new TalkPacket());
handlers.Add(22, new TalkPacket());
handlers.Add(11, new TalkPacket());
My question is about the references why create more objects.. when you can re-use them.
So really I'm unsure does the ugly way only make one instance of TalkPacket object or 4? like the elegant way, if there is no difference with the code above. Then I might as well go with the elegant way.
I only will be including no more then 255 packets anyways so 255 objects big deal.. but most of the packets will be shared with other opcodes which is why I keep thinking why initiate more instances when they do the same thing.
At first i was looking for a way to bind multiple int datatypes to one object and having easy access like the TryGetValue command.
Anyways if anyone has any good suggestions let me know. Thanks.
The first way there is only one instance of TalkPacket created and all the 4 entries in the Dictionary reference this single instance.
In the second one, there are 4 different objects of type TalkPacket.
So no, these two are not equivalent.
You don't need a dictionary for this:
on the dictionary where you do:
PacketHandler temp;
temp = new TalkPacket();
handlers.Add(33, temp);
handlers.Add(66, temp);
handlers.Add(22, temp);
handlers.Add(11, temp);
is the same as:
private static PacketHandler handler = new TalkPacket();
public static void HandlePacket(Player player, Packet p)
{
PacketHandler handler = null;
if(idList.Contains(p.Id)) { // no need for dictionary, just array or list of int
handler.handlePacket(player, p);
} else {
Console.WriteLine("Unhandled packet: " + p + ".");
}
}
While the second method you proposed is the same as:
public static void HandlePacket(Player player, Packet p)
{
PacketHandler handler = null;
if(idList.Contains(p.Id)) { // no need for dictionary, just array or list of int
handler = new TalkPacket();
handler.HandlePacket(player, p);
} else {
Console.WriteLine("Unhandled packet: " + p + ".");
}
}
The second approach is slower.
I have 3 comboboxes that are loaded with data from LINQ queries on page load. The problem is that queries contain so much data that it causes Internet Explorer to stop responding for a bit more than a minute.
As there are 3 queries my idea is to put them in 3 different threads, but the problem is at the end the only thing I get is the error saying: "Both DataSource and DataSourceID are defined on 'cbOrganizator'. Remove one definition."
cbOrganizator is a combobox.
Here is the code:
protected void Page_Load(object sender, EventArgs e)
{
Bind();
}
public void Osobe()
{
PravosudnaAkademijaEntities db = new PravosudnaAkademijaEntities();
var osoba = from o in db.osobas
orderby o.osoba_prezime
select new { o.osoba_id, imePrezime = o.osoba_prezime + " " + o.osoba_ime + " | " + o.tijelo.tijelo_naziv + " | " + o.radno_mjesto.rm_naziv_m };
cbPolaznik.DataSource = osoba;
cbPolaznik.DataTextField = "imePrezime";
cbPolaznik.DataValueField = "osoba_id";
cbPolaznik.DataBind();
cbPolaznik.Items.Insert(0, " ");
cbPredavac.DataSource = osoba;
cbPredavac.DataTextField = "imePrezime";
cbPredavac.DataValueField = "osoba_id";
cbPredavac.DataBind();
cbPredavac.Items.Insert(0, " ");
cbAOM.DataSource = osoba;
cbAOM.DataTextField = "imePrezime";
cbAOM.DataValueField = "osoba_id";
cbAOM.DataBind();
cbAOM.Items.Insert(0, " ");
}
public void Tijela()
{
PravosudnaAkademijaEntities db = new PravosudnaAkademijaEntities();
var tijelo = from t in db.tijeloes
orderby t.tijelo_naziv
select new { t.tijelo_id, sve = t.tijelo_naziv + " | " + t.mjesto.zupanija_drzava.zupanija_naziv };
cbOrganizator.DataSource = tijelo;
cbOrganizator.DataTextField = "sve";
cbOrganizator.DataValueField = "tijelo_id";
cbOrganizator.DataBind();
cbOrganizator.Items.Insert(0, " ");
}
public void Bind()
{
Thread tOsobe = new Thread(Osobe);
tOsobe.Start();
Thread tTijela = new Thread(Tijela);
tTijela.Start();
}
I don't know what's wrong so any help would be appreciated. The primary idea is to separate queries into threads so if my approach is wrong please let me know.
You're starting threads but not giving them a chance to finish before the page is loaded. I don't know how that results in your particular error, but if your page loads before the thread is completed, then you definitely won't get results.
I really don't see how you'll be able to accomplish what you're trying to do without AJAX.
if you do really want to do it with threads i would suggest performing the query on the threadpool. you can abstract your method so that it is called in delegate of the threadpool method
so i would replace bind with
ThreadPool.QueueUserWorkItem(new WaitCallback(Osobe));
ThreadPool.QueueUserWorkItem(new WaitCallback(Tijela));
change signature of Osobe, and Tijela to acccept a Object
eg.public void Osobe(object a )
you will also need to marshal the call across the thread as i am not sure if webforms will accept if the binding is happening on another thread.
All said and done is still feel the ajax method is the best way forward.
I've written a simple class for debugging and I call the method Debugger.WriteLine(...) in my code like this:
Debugger.WriteLine("[Draw]", "InProgress",
"[x,y] = " + x.ToString("0.00") +
", " + y.ToString("0.00") +
"; pos = " + lastPosX.ToString() + "x" +
lastPosY.ToString() + " -> " + posX.ToString() +
"x" + posY.ToString() + "; SS = " +
squareSize.ToString() + "; MST = " +
startTime.ToString("0.000") + "; Time = " + time.ToString() +
phase.ToString(".0000") + "; progress = " +
progress.ToString("0.000") + "; step = " +
step.ToString() + "; TimeMovementEnd = " +
UI.MovementEndTime.ToString()
);
The body of the procedure Debugger.WriteLine is compiled only in Debug mode (directives #if, #endif). What makes me worry is that I often need ToString() in Debugger.WriteLine call which is costly because it creates still new strings (for changing number for example). How to solve this problem?
A few points/questions about debugging/tracing:
I don't want to wrap every Debugger.WriteLine in an IF statement or to use preprocessor directives in order to leave out debugging methods because it would inevitable lead to a not very readable code and it requires too much typing.
I don't want to use any framework for tracing/debugging. I want to try to program it myself.
Are Trace methods left out if compiling in release mode? If it is so is it possible that my methods would behave similarly?
With the static String.Format method I can do this:
output = String.Format("You are now {0} years old.", years);
Which seems nice. Is it a solution for my problem with ToString()?
Using Reflector I found out that Debug.Writeline is declared this way :
[Conditional("DEBUG")]
public static void WriteLine(string message)
That means that in Release mode all calls to this method are eliminated from code.
For example this code :
public static void Test(int a)
{
string b = Console.ReadLine();
Debug.WriteLine(a + " " + b);
Console.WriteLine(a + " " + b);
}
compiles in release mode to :
public static void Test(int a)
{
Console.WriteLine(a + " " + Console.ReadLine());
}
Use StringBuilder to create your output strings instead of concatenating each and every value.
And you can create your own custom debugger (MyDbg) class that contains a WriteLine member the contents of which you can surround with compile directives. It wouldn't entirely compile out the debug code but would turn you MyDbg.WriteLine calls into no-ops.
Here's a quick sketch of the class:
using System;
using System.Text ;
public static class MyDbg
{
public static void WriteLine(string str) // and some other params
{
#if DEBUG
StringBuilder sb = new StringBuilder();
sb.Append(str);
// etc. appending other params as you see fit
#endif
}
}
OR
[Conditional("DEBUG")]
public static class MyDbg
{
public static void WriteLine(string str) // and some other params
{
StringBuilder sb = new StringBuilder();
sb.Append(str);
// etc. appending other params as you see fit
}
}
You'd modify it to suit your own needs of course. And instead of creating a separate class, you could create a member method if #if DEBUG/#endif built-in for displaying its own state when in the debugger.
For Logging have a look at frameworks such as Log4net or the Enterprise library. They make logging configurable in many ways. Even if you want to log at all.
HTH
The pattern I use is to define a logging interface (ILogger) that gets dependency injected into all the classes
public class MyClassThatLogs
{
public MyClassThatLogs(ILogger logger)
{
try
{
logger.Write("bla bla bla");
}
catch(Exception ex)
{
logger.Write(ex); //overload of Write() that takes in an Exception
}
}
}
So when you new it up you can pass in a 'real' logger or a mock/fake one
var mc = new MyClassThatLogs(new FakeLogger());
Now you have abstracted away the need to know in the MyClassThatLogs class what's going on with logging. Basic SOLID stuff. So the 'top' (say main() method of a console) would have the IF DEBUG directive then pass in the correct implementation of the logger.
You do not need to wrap every line. Just write helper method containing Debug.WriteLine and turn it on/off by flag (usually bool).
Tracing will be in your code even in release mode. You can configure it, see http://msdn.microsoft.com/en-us/library/system.diagnostics.tracelistener.aspx
string.Format calls ToString() on arguments internally, so no benefit there.