From 307fd830eb168005a3ba3d557343284814757eff Mon Sep 17 00:00:00 2001 From: Benoit Germain Date: Tue, 3 Dec 2024 10:26:47 +0100 Subject: New method linda:restrict() --- docs/index.html | 132 +++++++++++++++++++++++++++++++++----------------------- 1 file changed, 77 insertions(+), 55 deletions(-) (limited to 'docs') diff --git a/docs/index.html b/docs/index.html index 7432c53..6757981 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1218,7 +1218,7 @@ lane_h = lanes.gen("", loop)(10000) while true do - local key, val = linda:receive(3.0, "x") -- timeout in seconds + local slot, val = linda:receive(3.0, "x") -- timeout in seconds if val == nil then print("timed out") break @@ -1233,7 +1233,7 @@ Characteristics of the Lanes implementation of lindas are:

- set() can write several values at the specified key. Writing nil values is possible, and clearing the contents at the specified key is done by not providing any value.
+ set() can write several values at the specified slot. Writing nil values is possible, and clearing the contents at the specified slot is done by not providing any value.
If set() actually stores data, the linda is signalled for write, so that receive()-blocked Lanes are awakened.
- Clearing the contents of a non-existent key does not create it!
- If the key was full but the new data count of the key after set() is below its limit, set() first return value is true and the linda is also signaled for read, so that send()-blocked Lanes are awakened.
- If the key was not already full, nothing additional happens, and set() first return value is false.
- The second return value is a string representing the fill status relatively to the key's current limit (one of "over", "under", "exact"). + Clearing the contents of a non-existent slot does not create it!
+ If the slot was full but the new data count of the slot after set() is below its limit, set() first return value is true and the linda is also signaled for read, so that send()-blocked Lanes are awakened.
+ If the slot was not already full, nothing additional happens, and set() first return value is false.
+ The second return value is a string representing the fill status relatively to the slot's current limit (one of "over", "under", "exact").

@@ -1374,25 +1395,26 @@

-	[val] = linda_h:count([key[,...]])
+	[val] = linda_h:count([slot[,...]])
 

Returns some information about the contents of the linda.
- If no key is specified, and the linda is empty, returns nothing.
- If no key is specified, and the linda is not empty, returns a table of key/count pairs that counts the number of items in each of the exiting keys of the linda. This count can be 0 if the key has been used but is empty.
- If a single key is specified, returns the number of pending items, or nothing if the key is unknown.
- If more than one key is specified, return a table of key/count pairs for the known keys. + If no slot is specified, and the linda is empty, returns nothing.
+ If no slot is specified, and the linda is not empty, returns a table of slot/count pairs that counts the number of items in each of the exiting slots of the linda. This count can be 0 if the slot has been used but is empty.
+ If a single slot is specified, returns the number of pending items, or nothing if the slot is unknown.
+ If more than one slot is specified, return a table of slot/count pairs for the known slots.

 	linda_h:dump() ->
 	{
-		[<key>] =
+		[<slot>] =
 		{
 			first = <n>
 			count = <n>
 			limit = <n>|'unlimited'
+			restrict = "none"|"set/get"|"send/receive"
 			fifo = { <array of values> }
 		}
 		...
@@ -1458,7 +1480,7 @@
 		
 
 		
  • - Namespace control. linda keys have a "flat" namespace, so collisions are possible if you try to use the same linda for too many separate uses. + Namespace control. linda slots have a "flat" namespace, so collisions are possible if you try to use the same linda for too many separate uses.
  • @@ -1467,7 +1489,7 @@
  • - On the other side, you need to use a common linda for waiting for multiple keys. You cannot wait for keys from two separate linda objects at the same time. + On the other side, you need to use a common linda for waiting for multiple slots. You cannot wait for slots from two separate linda objects at the same time.

    @@ -1480,7 +1502,7 @@

    Timers

    -	void = lanes.timer(linda_h, key, date_tbl|first_secs [,period_secs])
    +	void = lanes.timer(linda_h, slot, date_tbl|first_secs [,period_secs])
     

    @@ -1492,7 +1514,7 @@

    - Once a timer expires, the key is set with the current time (in seconds, same offset as os.time() but with millisecond accuracy). The key can be waited upon using the regular linda :receive() method. + Once a timer expires, the slot is set with the current time (in seconds, same offset as os.time() but with millisecond accuracy). The slot can be waited upon using the regular linda :receive() method.

    @@ -1517,13 +1539,13 @@ lanes.timer(linda, "min", t, 60) -- reoccur every minute (sharp) while true do - local key, v = linda:receive("sec", "min") - print("Timer "..key..": "..v) + local slot, v = linda:receive("sec", "min") + print("Timer "..slot..": "..v) end

    - NOTE: Timer keys are set, not queued, so missing a beat is possible especially if the timer cycle is extremely small. The key value can be used to know the actual time passed. + NOTE: Timer slots are set, not queued, so missing a beat is possible especially if the timer cycle is extremely small. The slot value can be used to know the actual time passed.

    @@ -1533,7 +1555,7 @@ Having the API as lanes.timer() is intentional. Another alternative would be linda_h:timer() but timers are not traditionally seen to be part of lindas. Also, it would mean any lane getting a linda handle would be able to modify timers on it. A third choice could be abstracting the timers out of linda realm altogether (timer_h= lanes.timer(date|first_secs, period_secs )) but that would mean separate waiting functions for timers, and lindas. - Even if a linda object and key was returned, that key couldn't be waited upon simultaneously with one's general linda events. + Even if a linda object and slot was returned, that slot couldn't be waited upon simultaneously with one's general linda events. The current system gives maximum capabilities with minimum API, and any smoothenings can easily be crafted in Lua at the application level. @@ -1578,7 +1600,7 @@

    -	lock_func|lanes.cancel_error = lanes.genlock(linda_h, key [,N_uint=1])
    +	lock_func|lanes.cancel_error = lanes.genlock(linda_h, slot [,N_uint=1])
     
     	bool|lanes.cancel_error = lock_func(M_uint [, "try"] )     -- acquire
     	..
    @@ -1604,13 +1626,13 @@
     

    -	atomic_func|lanes.cancel_error = lanes.genatomic(linda_h, key [,initial_num=0.0])
    +	atomic_func|lanes.cancel_error = lanes.genatomic(linda_h, slot [,initial_num=0.0])
     
     	new_num|lanes.cancel_error = atomic_func([diff_num=+1.0])
     

    - Each time called, the generated function will change linda[key] atomically, without other lanes being able to interfere. The new value is returned. You can use either diff 0.0 or get to just read the current value. + Each time called, the generated function will change linda[slot] atomically, without other lanes being able to interfere. The new value is returned. You can use either diff 0.0 or get to just read the current value.

    @@ -1632,7 +1654,7 @@

  • Booleans, numbers, strings, light userdata, Lua functions and tables of such can always be passed.
  • Cyclic tables and/or duplicate references are allowed and reproduced appropriately, but only within the same transmission. - Using the same source table in multiple linda messages keeps no ties between the tables (this is the same reason why tables can't be used as keys). + Using the same source table in multiple linda messages keeps no ties between the tables (this is the same reason why tables can't be used as slots).
  • For tables and full userdata: before anything else, the metatable is searched for a __lanesconvert field. If found, the source object is converted as follows depending on __lanesconvert's value: @@ -1914,7 +1936,7 @@ static MyDeepFactory g_MyDeepFactory;
    • Data passing (arguments, upvalues, linda messages) is generally fast, doing two binary state-to-state copies (from source state to hidden state, hidden state to target state). Remember that not only the function you specify but also its upvalues, their upvalues, etc. etc. will get copied.
    • Lane startup is fast (1000's of lanes a second), depending on the number of standard libraries initialized. Initializing all standard libraries is about 3-4 times slower than having no standard libraries at all. If you throw in a lot of lanes per second, make sure you give them minimal necessary set of libraries.
    • -
    • Waiting lindas are woken up (and execute some hidden Lua code) each time any key in the lindas they are waiting for are changed. This may give essential slow-down (not measured, just a gut feeling) if a lot of linda keys are used. Using separate lindas for logically separate issues will help (which is good practice anyhow).
    • +
    • Waiting lindas are woken up (and execute some hidden Lua code) each time any slot in the lindas they are waiting for are changed. This may give essential slow-down (not measured, just a gut feeling) if a lot of linda slots are used. Using separate lindas for logically separate issues will help (which is good practice anyhow).
    • linda objects are light. The memory footprint is two OS-level signalling objects (HANDLE or pthread_cond_t) for each, plus one C pointer for the proxies per each Lua state using the linda. Barely nothing.
    • Timers are light. You can probably expect timers up to 0.01 second resolution to be useful, but that is very system specific. All timers are merged into one main timer state (see timer.lua); no OS side timers are utilized.
    • If you are using a lot of linda objects, it may be useful to try having more of these Keeper states. By default, only one is used (see lanes.configure()).
    • -- cgit v1.2.3-55-g6feb