Skip to content

Thread synchronization

Forums Forums SIMPOL Programming Thread synchronization

Viewing 4 posts - 1 through 4 (of 4 total)
  • Author
    Posts
  • #287
    Jim Locker
    Member

    There appears to be no mechanism in simpol to synchronize threads. The one mechanism available appears to be to use a common variable that is read by multiple threads to determine whether it is OK to take an action or not. But, lacking mutual exclusion locks and/or the capability to prevent context switches, this leads to the obvious race condition of: thread reads variable and determines action is OK, then starts to take action. But between the time thread reads variable and time thread starts to take action, another thread sets variable to block action and takes competing action. So, either the race is a real concern or something about how simpol handles threads keeps the race from being a concern at all. If, for instance, simpol only switches contexts and threads when the currently running thread drops into wxprocess, then all is OK. So, how does simpol handle its threads? My usual design philosophy has me opening a database file, performing my operation, and immediately closing the file. In a single user environment this isn’t important, necessarily, if file handle usage isn’t important, but in any kind of multi-user environment this becomes rather critical – particularly on Windows. But, in playing with my Request20 (which I have given a drilldown option) I am encountering intermittent errors if I type too fast that “the table cannot be opened”…presumably because I already have it opened and am trying to open it again. The obvious solution is to test for, and grab if it exists, the object for the currently open file handle. The obvious danger is that between the time I test for the handle and the time I grab it, someone else closes it. I do multi-thread and multi-process stuff all the time, and in high-reliability and critical environments. Avoiding races and ensuring synchronization is de rigeur, and I am good at it. So I won’t deploy a solution that might have a race in it that I know about, particularly when the language won’t let me trap the resulting intermittent run-time error. I also test the hell out of things to find races I might not know about. So, how do I avoid race conditions? How does simpol handle this?

    #1640
    Michael
    Keymaster

    Jim wrote:
    > There appears to be no mechanism in simpol to synchronize threads.
    > The one mechanism available appears to be to use a common variable
    > that is read by multiple threads to determine whether it is OK to
    > take an action or not.
    >
    > But, lacking mutual exclusion locks and/or the capability to prevent
    > context switches, this leads to the obvious race condition of:
    > thread reads variable and determines action is OK, then starts to
    > take action. But between the time thread reads variable and time
    > thread starts to take action, another thread sets variable to block
    > action and takes competing action.

    They can't. Once the lock has been granted tot he first thread, if the
    second thread attempts the exclusive lock, it will fail, at which point
    it should wait in a loop until it can succeed.

    > So, either the race is a real concern or something about how simpol
    > handles threads keeps the race from being a concern at all. If, for
    > instance, simpol only switches contexts and threads when the
    > currently running thread drops into wxprocess, then all is OK.
    >
    > So, how does simpol handle its threads?

    SIMPOL does its own round-robin checking of threads. It is also aware of
    deadly embrace scenarios. If you use the lock1 object, you should be
    able to synchronize access between threads successfully.

    > My usual design philosophy has me opening a database file, performing
    > my operation, and immediately closing the file. In a single user
    > environment this isn't important, necessarily, if file handle usage
    > isn't important, but in any kind of multi-user environment this
    > becomes rather critical – particularly on Windows.

    Unnecessary in SIMPOL. The SIMPOL single-user engine uses 1 file handle
    per database container. The multi-user engine uses UDP/IP, so it uses no
    file handles.

    > But, in playing with my Request20 (which I have given a drilldown
    > option) I am encountering intermittent errors if I type too fast that
    > "the table cannot be opened"…presumably because I already have it
    > opened and am trying to open it again.

    Leave it open.

    > The obvious solution is to test for, and grab if it exists, the
    > object for the currently open file handle. The obvious danger is
    > that between the time I test for the handle and the time I grab it,
    > someone else closes it.

    ? Open the table at the beginning, and store the handle in an
    application level object. This is how SIMPOL Personal works. It stores
    datasources at the application level, and tables at the window level.

    > I do multi-thread and multi-process stuff all the time, and in
    > high-reliability and critical environments. Avoiding races and
    > ensuring synchronization is de rigeur, and I am good at it.
    >
    > So I won't deploy a solution that might have a race in it that I know
    > about, particularly when the language won't let me trap the
    > resulting intermittent run-time error. I also test the hell out of
    > things to find races I might not know about.
    >
    > So, how do I avoid race conditions? How does simpol handle this?

    I think you are probably over-engineering this. Don't close the tables,
    keep them open. The resource hit is minimal in single-user, and
    non-existent in multi-user. As for race conditions, they are rare in
    SIMPOL, but if you use lock1 correctly, that will let you control
    synchronization.

    Ciao, Neil

    #1825
    Jim Locker
    Member

    Neil Robinson wrote:

    > Jim wrote:
    >> There appears to be no mechanism in simpol to synchronize threads.
    >> The one mechanism available appears to be to use a common variable
    >> that is read by multiple threads to determine whether it is OK to
    >> take an action or not.
    >>
    >> But, lacking mutual exclusion locks and/or the capability to prevent
    >> context switches, this leads to the obvious race condition of:
    >> thread reads variable and determines action is OK, then starts to
    >> take action. But between the time thread reads variable and time
    >> thread starts to take action, another thread sets variable to block
    >> action and takes competing action.

    > They can't. Once the lock has been granted tot he first thread, if the
    > second thread attempts the exclusive lock, it will fail, at which point
    > it should wait in a loop until it can succeed.

    >> So, either the race is a real concern or something about how simpol
    >> handles threads keeps the race from being a concern at all. If, for
    >> instance, simpol only switches contexts and threads when the
    >> currently running thread drops into wxprocess, then all is OK.
    >>
    >> So, how does simpol handle its threads?

    > SIMPOL does its own round-robin checking of threads. It is also aware of
    > deadly embrace scenarios. If you use the lock1 object, you should be
    > able to synchronize access between threads successfully.

    >> My usual design philosophy has me opening a database file, performing
    >> my operation, and immediately closing the file. In a single user
    >> environment this isn't important, necessarily, if file handle usage
    >> isn't important, but in any kind of multi-user environment this
    >> becomes rather critical – particularly on Windows.

    > Unnecessary in SIMPOL. The SIMPOL single-user engine uses 1 file handle
    > per database container. The multi-user engine uses UDP/IP, so it uses no
    > file handles.

    >> But, in playing with my Request20 (which I have given a drilldown
    >> option) I am encountering intermittent errors if I type too fast that
    >> "the table cannot be opened"…presumably because I already have it
    >> opened and am trying to open it again.

    > Leave it open.

    >> The obvious solution is to test for, and grab if it exists, the
    >> object for the currently open file handle. The obvious danger is
    >> that between the time I test for the handle and the time I grab it,
    >> someone else closes it.

    > ? Open the table at the beginning, and store the handle in an
    > application level object. This is how SIMPOL Personal works. It stores
    > datasources at the application level, and tables at the window level.

    >> I do multi-thread and multi-process stuff all the time, and in
    >> high-reliability and critical environments. Avoiding races and
    >> ensuring synchronization is de rigeur, and I am good at it.
    >>
    >> So I won't deploy a solution that might have a race in it that I know
    >> about, particularly when the language won't let me trap the
    >> resulting intermittent run-time error. I also test the hell out of
    >> things to find races I might not know about.
    >>
    >> So, how do I avoid race conditions? How does simpol handle this?

    > I think you are probably over-engineering this. Don't close the tables,
    > keep them open. The resource hit is minimal in single-user, and
    > non-existent in multi-user. As for race conditions, they are rare in
    > SIMPOL, but if you use lock1 correctly, that will let you control
    > synchronization.

    > Ciao, Neil

    Somehow I missed the lock1 object. That, of course, is just what I need.

    I have this almost religious dislike for leaving tables open. But if that
    is the way, then that is what I will do.

    I take it that all simpol networking is ppcs (of course, I could set up a
    tcp socket and so forth, but that isn't built in networking).

    If this is true, then I would need to run a ppcs server for any
    networkable version of my package?

    #1682
    Michael
    Keymaster

    Jim wrote:
    > Somehow I missed the lock1 object. That, of course, is just what I
    > need.

    🙂

    > I have this almost religious dislike for leaving tables open. But if
    > that is the way, then that is what I will do.

    It is easier. If you don't want them open permanently in a complex
    modular system with module-specific tables, then make those part of some
    object specific to the module, and let the object go out of scope when
    you exit the module.

    > I take it that all simpol networking is ppcs (of course, I could set
    > up a tcp socket and so forth, but that isn't built in networking).

    Yes.

    > If this is true, then I would need to run a ppcs server for any
    > networkable version of my package?

    That's right. See the Utilitiessimpolserver directory (readme.txt, etc.).

    Ciao, Neil

Viewing 4 posts - 1 through 4 (of 4 total)
  • You must be logged in to reply to this topic.