Modelling task A as an rdbms system, or my kv implementation, if one thread provides a sequence of set/add/get commands, then the get command should reflect the state of the rdbms as it is in the ordered execution of that sequence. If a different rdbms user, or equivalently, another thread, makes a query on the system, then it just cares about a non-crashing coherent state of that rdbms, knowing full well that at any time some other user/thread would update it, and that the query automatically is out of date to potential system.
dbms systems also have the concept of atomicizing multiple commands into a transaction: tied sets such that both sets must succeed in order to successfully update the dbms state. In my kv system, mykv =: (newstuff2 kvset newstuff1 kvset ]) t. '' mykv NB. atomic both set sequence must finish. mykv =: (newstuff2 kvset t.'' newstuff1 >@kvset t.'' ]) mykv NB. still sequential because newstuff 2 must wait for first set to complete. In these examples, even if the 2nd is not atomic, the global variable update is dependent upon both sets/updates occurring. A problem with the current implementation is that the new value of mykv has an extra boxing level because it is a pyx instead of the kv. A non-problem is whether other threads would access "old data", because the nature of the datasystem is that data is always old at time of acquisition. The natural way to create side effects with t. in J, without caring about a return value is: ". t.'' 'mykv =: (newstuff2 kvset newstuff1 >@kvset ]) mykv' and where updates need not be atomic then a verb called as (newstuff1, newstuff2) f 'mykv' could generate updates to mykv as a sequence (with intermediate updates available to other threads) of updates in ". format. The functional approach to update/append is to return the full updated data result from the function. The anti-functional approach is to just update the variable holding the data. The antifunctional approach can still leverage the functional result. It would seem to me that the datacopying overhead of threads is a bigger concern than ensuring the most updated access to variable than may be modified in other threads. Asynchronous programming that does not wait on a result, must pretty much always, send result to a global variable. The ". 'myvar =:...' format will be a crutch. and myvar must already exist to be accessible-assumed from other threads. To answer your question directly, If task A owns myvar, then any read locks on myvar imposed on other threads while myvar is being updated, are freed when myvar =: functionresult is executed is one option, but a perfectly valid alternative, is that any other tasks can access the "old value" of myvar even while a function in task A is updating it. ie. the lock only occurs at the =: operation stage. Not the longer myvar =: [x] f t.'' y stage. On Thursday, April 14, 2022, 03:25:21 p.m. EDT, Henry Rich <[email protected]> wrote: If task A own a variable, and task B uses it, how does A know when it is safe to make changes? Henry Rich On 4/14/2022 3:18 PM, 'Pascal Jasmin' via Beta wrote: >> If task A wants to send info > repeatedly to task B, say in a global name, there has to be a watertight > way for B to know when the data is ready and for A to know when it is > safe to overwrite it. > > > The current t.'' implementation has 0 task interchange mechanisms. My idea > of a thread owning a variable, would permit querying subsets of it from other > threads, where subsets are a smaller data transfer burden, and data transfer > burden is the main determinant of system throughput threading overhead. > > Where "data interchange between threads" is done with the n parameter to t., > then I don't understand the potential compared to my proposals. > > > > > > > On Thursday, April 14, 2022, 02:41:31 p.m. EDT, Henry Rich > <[email protected]> wrote: > > > > > > You give a good catalog of the reasons multithreading is worth doing! > > Assignment is already atomic (in the upcoming beta-c where some more > bugs are fixed). You can assign and delete names at will and threads > won't crash. > > BUT I am sure that more is needed. If task A wants to send info > repeatedly to task B, say in a global name, there has to be a watertight > way for B to know when the data is ready and for A to know when it is > safe to overwrite it. That's what I was talking about. > > If a task always starts with all the information it needs, no further > synchronization is required. > > Henry Rich > > On 4/14/2022 2:31 PM, 'Pascal Jasmin' via Beta wrote: >> My usual jbreak invocation (haven't tried on j904 yet) is to invoke it 2-5 >> times, because there is rarely an immediate response from J. I have no idea >> whether the extra invocations actually help, other than bashing the command >> has no competing use for my time, in those moments. >> >>> If the user issues a second break before the >> ATTN has been noticed, it will force immediate termination of all tasks >> with the 'break' error. >> >> You're suggesting that a single jbreak might preserve more information to >> inspect. I'm not sure if this is current single threaded behaviour, and a >> 2nd jbreak press, can indeed achieve quicker break by losing the necessary >> coherence with the "softer" error of a single jbreak. >> >> As to, unrelated, your general release statement was to "work on a >> mutex/locking J enhancement primitives." : >> >> There has been a lot of recent work, by you, to make in-placed code for >> efficiency. It would certainly benefit threaded code as well. >> >> From a user perspective, if there was just an internal locking mechanism >>that made =: =. "atomic" such that read/write accesses were blocked until the >>assignments were complete, then there is nothing the user is forced to >>consider in order to safely read/write variables. Reading threads being >>automatically blocked until =: completes, or inplace + =: operation completes. >> >> With that said, my kv implementation could be structured with internal >> threading benefits. A global variable or object reference being explicity >> assigned to a thread (such that no copying is needed when >> accessing/communicating with that variable/object, ie. thread already knows >> its, potentially large, internal data, and if that global/object is y, then >> only the function and x needs to be sent to the thread, provide greater >> system throughput, even if it means queueing commands/read/write access to a >> thread. This "thread owns a global/object" functionality would reduce the >> need for alternate zeromq control of "datastructures" instead of the >> benefits of just t. 'myglobalvar'. >> >> So instead of users manually locking variables, locking being automagical >> would be a user benefit. One alterative interpretations of of f t. 'G' >> would be G =: [x] f t. '' G. ie. an implied y from conjunction. A >> definition of a perfect function is one that can be fed as (u^:) such that >> the result is of compatible shape for reapplication of u, and so the result >> is a good candidate for replacing the variable containing y. There are many >> f s, and an encouragement to design f s such that that f t. 'G' would be >> useful to J programmers, and unlike my previous suggestion, instead of >> allocating G to a specific thread, it would just provide enough info to lock >> reads from other threads until the operation completes. >> >> >> >> >> >> On Thursday, April 14, 2022, 12:18:48 p.m. EDT, Henry Rich >> <[email protected]> wrote: >> >> >> >> >> >> The next beta will support jbreak in multiple threads, as follows: >> >> Recall that running jbreak once raises the ATTN condition. This is a >> gentle tap on the shoulder, asking JE to stop at the start of a new >> sentence. A thread that is stopped by ATTN can be restarted reliably. >> Running jbreak a second time raises the BREAK condition. This poleaxes >> JE into immediate insensibility, possibly in the middle of a sentence, >> and you are on your own to decide whether continuation is feasible. >> >> When debug suspension is disabled, a single jbreak will be detected by >> the first task that starts a sentence. That task will fail with an >> 'attention interrupt' error. The system will then automatically >> simulate a second jbreak to force quick termination of all other tasks >> with the 'break' error. If the user issues a second break before the >> ATTN has been noticed, it will force immediate termination of all tasks >> with the 'break' error. >> >> When debug suspension is enabled, a single jbreak will be noticed by all >> tasks when they start a sentence or when they wait for a pyx after >> another task has noticed the break. After all tasks have noticed the >> break, the system enters debug suspension. The first thread that >> noticed the break will be the debug thread and the others will be >> dormant until execution is resumed. If the user issues a second break >> before the ATTN has been noticed, all tasks will interrupt their >> sentences as soon as possible to enter debug suspension with the 'break' >> error. You are on your own to decide whether continuation is feasible. >> >> There is no automatic detection of deadlock. double-jbreak is the only >> way out of deadlock/livelock. >> >> Henry Rich >> > -- This email has been checked for viruses by AVG. https://www.avg.com ---------------------------------------------------------------------- For information about J forums see http://www.jsoftware.com/forums.htm ---------------------------------------------------------------------- For information about J forums see http://www.jsoftware.com/forums.htm
