Click here to Skip to main content
15,888,733 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I'm making a program (acts as a Client) that communicates with multiple hardware devices (acts as Servers) using ethernet. If the user connects 2 hardware devices (box A and B) then I make 2 instances of these devices in software. Each of these 2 instances have each own instance of my ethernet class. This ethernet class can connect and have a WriteRead function. In my program each instance of the devices have it's own queue of commands that runs in it's own child thread. So thread 1 uses it's own instance of the ethernet class to communicate with box A and thread 2 uses it's own instance of the ethernet class to communicate with box B.

My problem is that when there is 2 hardware devices (or more) that my program is communicating with then the WriteRead function in my ethernet class often receives carbage bytes. If I use the lock keyword around all content of the WriteRead function and lock's on a STATIC instance of an object then it works (I get the correct byte array). If the lock instance is not static then it does not work (I get a too big byte array where a little part is correct and the rest is a lot of extra garbage bytes. It also starts with garbage bytes.). My first idea was that this is a thread problem. But how can it be a threading problem when each thread have it's own instance of my ethernet class to work with and no member variables is static (except the static lock object)?

My performance decrease a lot when having the static lock in the function WriteRead in the ethernet class because then box B must wait for box A to leave the function WriteRead before box B can go into this function. And box A and B is independent of each other.

This is only a part of my code. It has been rewritten to make it more short:

C#
public class CControl
{
   //Make instance of box A (hardware device 1)
   private CIOLayer boxA = new CIOLayer(); 

   //Make instance of box B (hardware device 2)
   private CIOLayer boxB = new CIOLayer(); 

   public CControl()
   {
       boxA.Connect("10.8.4.90");
       boxB.Connect("10.8.4.91");

       boxA.ExecuteCommand1(1); //Put command on a queue and execute on thread 1
       boxB.ExecuteCommand1(1); //Put command on a queue and execute on thread 2 
   }
}

public class CIOLayer
{
   private CEthernet _ethernet = new CEthernet();
   private CQueue _queue = new CQueue(); 
   private byte[] arrSend;
   private byte[] arrReceive;

   public void Connect(string IP)
   {
      _ethernet.Connect(IP);
   }

   public void ExecuteCommand1(UInt32 runID)
   {
       this._queue.AddToQueue(new CQueueEntity((par) =>
       {
           //Create arrSend by looking in the protocol of the device.

           arrReceive = _ethernet.WriteRead(arrSend);

           //The result arrReceive is wrong if a static lock is not used in WriteRead(...) in CEthernet. 
       }, new object[] { runID }));
   }
}

public class CQueue 
{
   ConcurrentQueue<CQueueEntity> _queueLowLevelCommands = new ConcurrentQueue<CQueueEntity>();

   public CQueue()
   {
       this.ExecuteQueueItems();
   }

   public void AddToQueue(CQueueEntity queueItem)
   {
      this._queueLowLevelCommands.Enqueue(queueItem);
   }

   public CQueueEntity DequeueFromQueue()
   {...}

   private void ExecuteQueueItems()
   {
      Task.Factory.StartNew(() =>
      {
          while (true)
          {
              CQueueEntity queueItem = this.DequeueFromQueue();

              queueItem.Execute(queueItem.Parameters);
          }
      }
   }
}

public class CEthernet
{
   //This lock object must be static, but why?
   private static volatile object _processLockEthernet = new object();
   private Socket _clientSock;

   public void Connect(string IP, int port = 6789)
   {
        this._clientSock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

        this._clientSock.Connect(IP, port);
   }

   public byte[] WriteRead(byte[] arr) 
   {
        //WHY will it only work when having this STATIC lock ??
        //If the lock object is not static then the received byte 
        //array contains carbage (in 90% of the cases).
        //Each instance of a box have it's own instance of this CEthernet class!
        lock (_processLockEthernet) 
        {
            _bytes = _clientSock.Send(this._byteListFromPC.ToArray());

            //Wait for data
            while (_clientSock.Available == 0){...}

            byte[] received = new byte[_clientSock.Available];
            _clientSock.Receive(received);

            return received;
        }
   }
}
Posted
Comments
henrikxx 20-Jan-15 15:28pm    
Does someone have a hint?

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900