Changes to concurrency model in Max 7?


    Nov 16 2014 | 4:32 pm
    I've been a Max user since version 1.0, back when I had a steam-powered Mac-Minus, and this is one of the most wow releases ever. Congratulations!
    I asked this question on the non-dev list last night and was directed here, though I have a little more information.
    First, the Max 6 dev kit works perfectly with Max 7 - for my project. Indeed, I moved to using the git submodule version (as opposed to requiring people to separately download the Max 6 SDK) and it worked perfectly first time.
    But I have a report from a very reliable user that my external crashes in a few minutes on Max 7 (but worked on Max 6). Well, in interesting news I can't reproduce this at all - my external stayed up for hours and didn't run into any anomalies.
    I understand this is nothing for the reader to go on and I'm not desperate and I still have a lot of arrows left in my quiver, but I am curious - was there are a major change to the concurrency model? Is there perhaps a little better documentation about "the best way to do it"?
    (If you are interested, you can see what I'm doing here - I get a real time update, prepare a list of atoms, call critical_enter(0);, emit the list of atoms, and call critical_exit(0);.)

    • Nov 17 2014 | 8:53 am
      Hi.
      At a glance, one problem is that you can't make outlet calls from within a thread lock. I'm surprised that it ever worked...
      hth aa
    • Nov 17 2014 | 9:14 am
      Beyond the lock, you generally shouldn't be making outlet calls on an arbitrary thread, either. It's a little unclear from the code where this callback is coming from, but I assume it's none of the main, scheduler or audio threads provided by Max. I would recommend using a clock to move this message to the scheduler thread (use a delay of 0), and eliminating the critical region.
      Jeremy
    • Nov 27 2014 | 3:56 pm
      Hello, thanks for the help and sorry for the delay getting back to you! I wanted to try it out and see.
      I fixed this up as per your instructions, and it seems to work fine. Now, it seemed to work for me before anyway :-) but now all my calls to output are as the result of a callback from clock, and therefore apparently safe. I expect to get the bug reporter to test it shortly...
      There's a complete trail of git commits here, and I squashed together all those commits into this one. (I was a little undisciplined in mixing refactorings and logic changes, but I'm doing this mainly for fun. :-))
      I think it's completely thread-safe, even if the Max thread started to lag behind the Leap Motion thread (which seems unlikely since the Leap Motion thread updates at a little over 30Hz).
      I use the "lock-swap" idiom, where you have multiple buffers, prepare everything without taking a mutex, and only lock the mutex for the tiny amount of time it takes to swap buffers, literally just swapping two pointers.
      In my evaluation of this, the mutex was entirely uncontended, which means that the locks and unlocks should always be a few instructions in user space (in modern Mac/Windows OSes). It's hard to imagine a scenario where things weren't already collapsing where that mutex would have any significant amount of contention...
      Next step - outputting dictionaries!