DevOpen, doesn´t open in shared mode?

Hi!

I have a device created, dBASE_DEV, that creates an DBF.

I then call this device from a number of functions primarily using DevOpen in mode 0. Defined as mode 0, not relying on default 0.
This works fine when one function at a time opens the device, does it's thing, and then closes it.

But when I then have a loop that opens the device and each 10seconds scans through it just reading what´s in it, not closing it while sleeping. That function crashes when an other function opens the device.

It sounds like mode 0, shared mode, wouldn´t cause this. But Iv´e also tried mode 16, read only. But I get the same result with it crashing.
If I debug I get the error for bad handle, so I guess that the mode isn't as shared as one would think..

Am I using the device wrong? Maybe it can´t be opened from more than one function at a time?

  • Hi Anders,

    If you call DevOpen repeatedly from within your loop code, you will get a handle leak and eventually you will be out of handles and/or memory.
    You will have to decide if you want to open your device once (before the loop starts) and keep it open the whole time, or if you want to open and close it each time from within the loop.

    Regards,
    Patrick
  • Hi!

    Thanks for the reply!

    My one loop-function only opens it once (in mode 16 at the moment, 0 didn´t work either) and keeps it open during scan and sleep.
    This works fine, but when another function opens the same device the loop-function crashes, when debugging I get error 269 - Bad handle specified, and the loop-function crashes.

    So I debugged it a bit more and found that my loop-function opens the device, and gets a handle number of 26.
    With that function running and with that handle thus open, I start another function that opens the same device, and gets the same handle number of 26! So when that function is finished it closes the handle and thus causes the loop-function to crash since the handle isn´t open anymore. Naturally.

    So the question is then, how do I get it to open it with a unique handle? Open in mode 1 - exclusive doesn´t seem right since that will cause other DevOpens to fail.
    Maybe open it on startup and use the same handle in all functions? But this is to be run on a redundant server with connected clients, all using these functions. Can the handle be shared so globally?
  • Well.. I have to reply to my self I suppose.
    If I actually would RTFM, and not just glance over it, it says right there in it:
    "You can use this function to return the handle of a device that is already open. The DevOpen() function does not physically open another device - it returns the same device handle as when the device was opened. The mode of the second open call is ignored. To re-open an open device in a different mode, you need to first close the device and then re-open it in the new mode."
    In summary: it won´t open a new handle if it´s already open.
    So that answers that.

    Question remains though if the handle can be used over several clients and servers.
    It´s a little bit hard to test, but that may be the only way I suppose.
  • Hi Anders,

    A handle is unique within a Citect process (client, I/O server, trend server, etc.). So you cannot share the handle across different machines and processes. A good place to store the handle is a MODULE or GLOBAL cicode variable, or a Local Variable tag.

    To be able to use the device from multiple machines/processes you have to open it in shared mode (or read only mode).
    To prevent conflicts you should also make sure that only one machine/process is writing to the device at the same time.

    I always try to prevent multiple access to a device if I can. For example, if I want to write log entries to a device, I would create a centralized logging function that runs only on the active server (say, the active report server process). All other machines and server processes would call this function using RPC (see MsgRPC cicode function).
  • Hi!

    A very comprehensive reply!

    I was thinking that I would have to resort to MsgRPC and run this on my report servers, just trying to avoid it.. ;)

    Thanks for all the help!
  • I tested this for a customer with a similar setup a number of years ago. They had multiple clients writing to the same log file on a file server. Each client would open the file, write a line, then quickly close the file. Normally they wouldn't conflict, but occasionally a client would get locked out and would refuse to open the file again until Windows was rebooted. Cicode error checking and device shared mode didn't help.

    The solution for them was, as Patrick said, to use MsgRPC() to send the messages to the Citect server, and then only the server wrote to the log file. An alternative, especially if you're writing a large amount of data or doing more than simple logging, would be to write to an SQL database--which is designed for multiple clients to connect simultaneously.
  • What are you trying to store in the device? There may be a better way...