6 Replies - 5936 Views - Last Post: 12 October 2007 - 11:55 AM Rate Topic: -----

#1 snoj  Icon User is offline

  • Married Life
  • member icon

Reputation: 84
  • View blog
  • Posts: 3,564
  • Joined: 31-March 03

Threading, variables, and "static" data...oh my!

Posted 09 October 2007 - 03:42 PM

So here at work, one of the things I do is write tools that make my IT life better. The tool I'm currently focused on is a net send replacement that comes in two parts. The first part is the client that sits on each machine and waits for sender/server to tell it what to say. The client is all fine and dandy, couldn't be better. However I'm having trouble with the sender, at least in a feature I want for it.

What I'm trying to do is to have the sender make a list of each computer on the network. Instead of it going through each computer on the "net view" list and querying it one at a time, I'm wanting to make threads that can do all of this at the same time.

My issue is that I can't seem to get the method (private void query(object cName)) to update the array (static string[] relations;) that is suppose to contain all this data unless I'm using the breakpoints to stop a thread. When I do that, the array is updated with the particular info from that computer that that thread is currently querying.

I'm pretty lost here. I've tried static making the relations array static, but to no avail. Am I missing some super important piece of the threading puzzle?

Here's my current code base. It's kinda messy since...well I'm new to C#, it's in development and some of it's copied from my previous attempts at threading and prior code to complete this task (the sequential version). [edit] This may not compile, as I'm sure I've changed some code since it last "worked" and I've been focused on other things the last few work days.
	class query_comp
	{
		private string[] comps;
		private Thread[] qThread;
		static public string[] relations;
		static public int remains;

		public query_comp(string[] comps)
		{
			this.comps = comps;
			this.qThread = new Thread[this.comps.Length];
			query_comp.relations = new string[this.comps.Length];
			query_comp.remains = this.comps.Length;

			for (int i = 0; i < this.qThread.Length; i++)
			{
				qThread[i] = new Thread(new ParameterizedThreadStart(this.query));
				qThread[i].Name = this.comps[i];
				qThread[i].Start((object) i);
				//qThread[i].Start();
			}
			MessageBox.Show("test");
		}

		private void query(object cName)
		{
			//string name = cName.ToString();
			int i = Int32.Parse(cName.ToString());
			query_comp.relations[i] = "blah:" + i;
			Console.WriteLine(i.ToString() + this.comps[i]);
			this.getInfo(i);
			query_comp.remains--;
		}

		private void getInfo(int ci)
		{
			//MessageBox.Show(((int)ci).ToString());
			//return;
			//string[] rtnArray = new string[2] {null,null};

			try
			{
				System.Net.IPHostEntry host = System.Net.Dns.GetHostEntry(this.comps[(int)ci]);
				TcpClient con = new TcpClient();

				//con.LingerState = new LingerOption(true, 5);
				con.ReceiveTimeout = 5;
				con.SendTimeout = 5;
				con.Connect(host.AddressList[0], 9090);


				if (con.Connected == true)
				{
					int i;
					NetworkStream stream = con.GetStream();
					stream.ReadTimeout = 5;
					stream.WriteTimeout = 5;
					string stringMsg = ":whoareyou\r\n";
					//byte byteMsg = new byte[stringMsg.Length];
					byte[] byteMsg = new byte[stringMsg.Length];

					for (i = 0; i < stringMsg.Length; i++)
					{
						byteMsg[i] = (byte)stringMsg[i];
					}

					stream.Write(byteMsg, 0, byteMsg.Length);

					if (stream.DataAvailable == true)
					{
						int rtn = 0;

						byte[] byteRead = new byte[con.ReceiveBufferSize];

						for (i = 0; (bool)(i < con.ReceiveBufferSize) && (rtn = stream.ReadByte()) != -1; i++)
						{
							byteRead[i] = (byte)rtn;
						}

						Array.Resize(ref byteRead, i);

						string[] msg = System.Text.Encoding.ASCII.GetString(byteRead, 0, byteRead.Length).Replace("\r", "").Replace("\n", "").Replace(" ", "").Split(new char[1] { (char)(byte)'|' }, 2);

						//MessageBox.Show("'" + msg[0]+"+" + msg[1]+ "'");
						lock (query_comp.relations)
						{
							query_comp.relations[(int)ci] = msg[0] + "|" + msg[1];
						}
						//this.UserCompRel = new string[msg.Length];
						//this.UserCompRel = (string[]) msg.Clone();
						// rtnArray = msg;
						stringMsg = ":quit\r\n";
						for (i = 0; i < stringMsg.Length; i++)
						{
							byteMsg[i] = (byte)stringMsg[i];
						}
						stream.Write(byteMsg, 0, byteMsg.Length);
					}
				}
				con.Close();
			}
			catch (SocketException se)
			{
				Console.Write(se.Data.ToString());
			}
			//Thread.CurrentThread.Abort();
		}
	}



Thanks Psycho and all others!

Is This A Good Question/Topic? 0
  • +

Replies To: Threading, variables, and "static" data...oh my!

#2 PsychoCoder  Icon User is offline

  • Google.Sucks.Init(true);
  • member icon

Reputation: 1639
  • View blog
  • Posts: 19,853
  • Joined: 26-July 07

Re: Threading, variables, and "static" data...oh my!

Posted 09 October 2007 - 03:48 PM

Snoj,

I actually have a class that retrieves all computer names & IP's at home that Ive used a couple times. When I get home Ill help you with this (I just don't have access to my home computer from here)
Was This Post Helpful? 0
  • +
  • -

#3 snoj  Icon User is offline

  • Married Life
  • member icon

Reputation: 84
  • View blog
  • Posts: 3,564
  • Joined: 31-March 03

Re: Threading, variables, and "static" data...oh my!

Posted 09 October 2007 - 03:53 PM

Psycho, it's not the computer names and IP's that I'm having trouble with. (I already have a class tool for that written.) It's that when I query each computer, I'm wanting to get the user who is using that computer (which the client returns when I query said computer) and with that build a computer/user relation table/array.
Was This Post Helpful? 0
  • +
  • -

#4 PsychoCoder  Icon User is offline

  • Google.Sucks.Init(true);
  • member icon

Reputation: 1639
  • View blog
  • Posts: 19,853
  • Joined: 26-July 07

Re: Threading, variables, and "static" data...oh my!

Posted 09 October 2007 - 03:59 PM

Ok now I understand, if you don't have a solution by the time I get home from work Ill help you come up with one. I'm already formulating somethings in my head lol, now I got something to think about on the way home :P
Was This Post Helpful? 0
  • +
  • -

#5 PsychoCoder  Icon User is offline

  • Google.Sucks.Init(true);
  • member icon

Reputation: 1639
  • View blog
  • Posts: 19,853
  • Joined: 26-July 07

Re: Threading, variables, and "static" data...oh my!

Posted 10 October 2007 - 05:11 AM

Snoj I owe you an apology, when I got home last night my life went into a tailspin (personal issues) and I never logged on to DIC, if you still need help with this let me know ok
Was This Post Helpful? 0
  • +
  • -

#6 serializer  Icon User is offline

  • D.I.C Head

Reputation: 0
  • View blog
  • Posts: 110
  • Joined: 25-June 07

Re: Threading, variables, and "static" data...oh my!

Posted 10 October 2007 - 07:47 PM

Hmmm... in
private void getInfo(int ci) { 
you lock query.relations when you write to it..

						lock (query_comp.relations)
						{
							query_comp.relations[(int)ci] = msg[0] + "|" + msg[1];
						}



..but you don't in some of the other functions. Multiple threads could be corrupting the object (if it's not just something much simpler - i haven't scrutinised the code too finely !)
Was This Post Helpful? 0
  • +
  • -

#7 snoj  Icon User is offline

  • Married Life
  • member icon

Reputation: 84
  • View blog
  • Posts: 3,564
  • Joined: 31-March 03

Re: Threading, variables, and "static" data...oh my!

Posted 12 October 2007 - 11:55 AM

Woohoo! I figured out the problem (special thanks to System.Console.WriteLine())! The issue was that I wasn't waiting (long enough) for client to respond, not that certain variables were or weren't locked! However in the future I will very likely integrate memory locks for when writing to the object variables.

Updated code with comments for those interested!
	class query_comp
	{
		static private string[] comps;
		static private Thread[] qThread;
		static public string[] relations;
		static public int remains;
		//static public ReaderWriterLock rwl = new ReaderWriterLock();

		public query_comp(string[] comps)
		{
			//Load the list of computers on the local network (list comes from jenet.localNet.netView())
			query_comp.comps = comps;
			//Array of threads for each TCP connection.
			query_comp.qThread = new Thread[query_comp.comps.Length];
			//The array of computer to user relations.
			query_comp.relations = new string[query_comp.comps.Length];
			//Number of connections left. Used for sleeping purposes outside of this context.
			query_comp.remains = query_comp.comps.Length;

			//Start each thread with the ID of the computer to query. (ID is for the query_comp.comps[] property)
			//There is likely a better way to do this.
			for (int i = 0; i < query_comp.qThread.Length; i++)
			{
				qThread[i] = new Thread(new ParameterizedThreadStart(query_comp.query));
				qThread[i].Name = query_comp.comps[i];
				qThread[i].Start((object) i);
			}
		}

		static private void query(object cName)
		{
			int i = Int32.Parse(cName.ToString());
			
			//Debugging code. Here for historical purposes.
			//Console.WriteLine(i.ToString() + ":" + query_comp.comps[i]);

			//Test for the ReadWriteLock methods.
			//Will likely use this in the future.
			/*query_comp.rwl.AcquireWriterLock(1000);
			try {
				query_comp.relations[i] = "blah:" + i + "|" + (new Random()).Next();
			}
			finally {
				query_comp.rwl.ReleaseWriterLock();
			}*/
			
			//Actually query the computer.
			//One reason for this being a seperate function is that the code for getInfo
			//is from a previous attempt and I'm to lazy to integrate it into this method.
			query_comp.getInfo(i);

			//Decrease the number of remaining computers to query.
			//Mainly used outside of this class for sleeping/progress bar purposes.
			query_comp.remains--;
		}


		static private void getInfo(int ci)
		{
			//sorry Yoda, in the programming world, there is a try.
			try
			{
				//Get the IP for the remote computer.
				System.Net.IPHostEntry host = System.Net.Dns.GetHostEntry(query_comp.comps[(int)ci]);

				//Initiate the TcpClient object.
				TcpClient con = new TcpClient();

				//Not sure what TcpLingerOption does exactly....
				//con.LingerState = new LingerOption(true, 5);

				//Set some timeouts so we don't hang forever!
				con.ReceiveTimeout = 5;
				con.SendTimeout = 5;

				//Connect to the first address we have for a given computer name.
				con.Connect(host.AddressList[0], 9090);

				//Debugging.
				//Console.WriteLine(Thread.CurrentThread.Name+" connection = " + con.Connected);
				
				//Okay...are we connected? Sweet lets do some stuff.
				if (con.Connected == true)
				{
					//i in this case serves many purposes related to sending and recieving messages.
					int i;

					//Connected, great, lets bring in the NetworkStream object.
					NetworkStream stream = con.GetStream();

					//Some more timeouts.
					stream.ReadTimeout = 5;
					stream.WriteTimeout = 5;

					//Ask who the client is.
					//Converts the string to a byte array.
					string stringMsg = ":whoareyou\r\n";
					byte[] byteMsg = new byte[stringMsg.Length];

					for (i = 0; i < stringMsg.Length; i++)
					{
						byteMsg[i] = (byte)stringMsg[i];
					}

					//Now to actually send the request.
					stream.Write(byteMsg, 0, byteMsg.Length);

					//No reply? Well lets just wait for a little bit.
					//At worst this will wait 10 seconds.
					for (int si = 0; si< 10 && stream.DataAvailable == false; si++)
					{
						Thread.Sleep((new Random()).Next(10) * 100);
					}

					//Debugging.
					//Console.WriteLine(Thread.CurrentThread.Name + " DataAvailable = " + stream.DataAvailable);

					//Sweet! We have some data to play with!
					if (stream.DataAvailable == true)
					{
						int rtn = 0;

						//So what did it say?
						byte[] byteRead = new byte[con.ReceiveBufferSize];

						for (i = 0; (bool)(i < con.ReceiveBufferSize) && (rtn = stream.ReadByte()) != -1; i++)
						{
							byteRead[i] = (byte)rtn;
						}

						Array.Resize(ref byteRead, i);

						//Convert the message from Bytes to ASCII for easy reading.
						//Also convert message into an array containing the computer and user info.
						string[] msg = System.Text.Encoding.ASCII.GetString(byteRead, 0, byteRead.Length).Replace("\r", "").Replace("\n", "").Replace(" ", "").Split(new char[1] { (char)(byte)'|' }, 2);

						//Any more and we have problems!
						if (msg.Length == 2)
						{
							query_comp.relations[(int)ci] = msg[0] + "|" + msg[1];
							Console.WriteLine(msg[0] + "|" + msg[1]);
						}
						
						//Debugging
						/*else
						{
							Console.WriteLine("Failed to write for: " + query_comp.comps[(int)ci]);
						}*/

						//Send the message to close the connection on the remote side.
						stringMsg = ":quit\r\n";
						for (i = 0; i < stringMsg.Length; i++)
						{
							byteMsg[i] = (byte)stringMsg[i];
						}
						stream.Write(byteMsg, 0, byteMsg.Length);
					}
				}
				//Close the connection.
				con.Close();
			}
			//Catch any exceptions
			catch (SocketException se)
			{
				Console.WriteLine("Unable to connect to " + Thread.CurrentThread.Name);
			}
		}
	}


Was This Post Helpful? 0
  • +
  • -

Page 1 of 1