1

I am working with an electrometer using RS-232(Serial) communication. It accepts one command at a time and sends back a response indicating if the command completed successfully or not.

For demonstration only consider the following method...

    private void SetDevice()
    {
        sc.SetBias();
        sc.SetRange();
        sc.SetCollectionTime();
        sc.SetID();
    }

The method signature for sc.SetID() is as follows.

    public void SetID()
    {
        ComPort.Write("*IDN?");
    }

The above gives you an idea of what the other individual command calls are like.

Since the DataReceived Event indicates it is raised on a secondary thread how should I proceed with waiting for a response between each command call? Presently after sc.SetBias() is called sc.SetRange() fires without regards to if the previous command executed successfully.

I can appreciate that by starting the DataReceivedEvent in a new thread it prevents my UI from locking but in this case when it is critical that the response gets paired with the appropriate command call I'm not sure of the best available option and would appreciate some guidance in my research. Thus far I'm considering getting a handle to the current UI thread and using Thread.Sleep(sleepTime) but without knowing exactly how reliable the response time is of the electrometer is this really best practice? And would this not need then to be called after every command sent?

TargetofGravity
  • 343
  • 1
  • 6
  • 14
  • Why not queue all the calls on a second thread? Make a common interface that you can push calls into a queue. The queue manager could then be in charge of making sure no two calls are happening at once. Sorry for no specifics I am not familiar with electrometers.i would highly suggest not using thread.sleep if this is under any sort of load you will spend more time context switching than actual computing. – Jamie Babineau Aug 25 '15 at 03:48
  • Just don't use DataReceived, it doesn't help you at all. Simply read the response directly after call Write(), usually with ReadLine(). You'll need the ReadTimeout property to avoid hangs. – Hans Passant Aug 25 '15 at 04:50

1 Answers1

0

If what you need is:

  1. Send a command
  2. Wait for response
  3. Send next command

Then you can use a Semaphore

It works like the following codes.

Semaphore _sync = new Semaphore(1, 1);
SerialPort _port;
...

void Send(...){
    _sync.WaitOne()
    _port.Send(...);
}

void _port_DataReceived(...){
    _sync.Release();
}

Take a try!

J.C
  • 633
  • 1
  • 13
  • 27
  • What about the use of `Thread.Join()`? I was reviewing the [following](http://stackoverflow.com/questions/2476552/what-is-the-significance-of-thread-join-method-in-c) thinking that if the `DataRecieved` event was fired on a new thread, but joined the current thread halting operations of the main thread until it finished this to would serve my purposes? – TargetofGravity Aug 26 '15 at 16:02
  • I tried what you suggested and perhaps I'm not understanding the API. It states "Limits the number of threads that can access a resource or pool of resources concurrently." In your example above would using `_sync.WaitOne()` then lock the send method until it is released? If that is the case since the `Send(...)` method in your example already fired I wouldn't need to have it locked. It is the methods that follow it that would need to lock. – TargetofGravity Aug 26 '15 at 16:02
  • I need to tell the main thread stop doing stuff until you hear back. This [MSDN](https://msdn.microsoft.com/en-us/library/tttdef8x(v=vs.110).aspx) listing discussing interrupting threads? @Jaime Babineau, I like the idea but am to new to development to fully know how to start the implementation of this.......will continue to work towards a solution to share for review. Thank you for the suggestions. – TargetofGravity Aug 26 '15 at 16:03
  • `Join()` is not suitable to your case (in my opinion). When A want to wait B finish, A join B, however, A must know "Who is B" so it can join. Sure, these's a new thread for `DataReceived` but you never know who's that thread when you just calling `Send`. – J.C Aug 26 '15 at 17:18
  • @TargetofGravity In my example, the running sequence is: Lock -> Send -> Received -> Release -> Lock -> Send -> Received -> Release, and it's what you need, right? You can not lock after send, because the sequence will be: Send -> Lock or Received, if Received faster then Lock, the sync has break and you will get a Semaphore exception. You can try to move the position of `Lock` by yourself, and see what will happen. – J.C Aug 26 '15 at 17:27
  • @TargetofGravity You better not block main thread, or the GUI will no response since GUI need the main thread to run it's message pipe. BTW, please tag me when you post a comment, or I may miss them. – J.C Aug 26 '15 at 17:31
  • I do appreciate you steering me towards the use of Semaphore. A modification I made to your above example that seems to be working is placing the `_sync.WaitOne()` after the method call to my `_port.Send()`. I know that the electrometer will always respond back to a command. If it doesn't then I have other issuIn addition – TargetofGravity Aug 28 '15 at 14:36
  • [This](http://stackoverflow.com/questions/34519/what-is-a-semaphore) link talks about using `Semaphore` as a signaling mechanism. In order to accomplish what I wanted I changed the example to `new Semaphore(0,1)`. I think in this case I want to lock the main thread because the execution of methods can be modified from the response. `new Semaphore(1,1)` allowed my main thread to continue to run which wasn't ideal unless I'm implementing this incorrectly. – TargetofGravity Aug 28 '15 at 14:47
  • @TargetofGravity Yep, the constructor of `Semaphore` is used to indicate how many token available in the beginning. I hope this answer could solve your problem. – J.C Aug 30 '15 at 12:04
  • @J Thank you for the guidance towards Semaphore. Because of that I felt it appropriate to mark your answer. Best regards. – TargetofGravity Aug 31 '15 at 16:13