So I have some threads where I would like to pass an upvalue called reset to each thread once every so often in order to reset each thread's table's values. I then want to switch off the reset until the table has finished iterating through its batches. However I have had no success in switching off the reset (reset = false) doesn't seem to stop it from continuously resetting.
for i = 1, n do
local reset = true
while true do
threads:addjob(
function()
if reset = true then f:reset(); reset = false; end
x,y = f:getBatch()
return x,y
end,
function(x,y)
-- do some stuff and trigger conditionMet = true if met
end
)
if conditionMet == true break end
end
end
Your upvalue "reset" here is read-only. The thread serializes "reset" and read it. So every iteration in the "while" loop, reset is read and serialized again by threads:addjob.
What you seem to want instead is to break it down this way:
for i = 1, n do
threads:addjob(
function()
__resetflag = true
end
)
while true do
threads:addjob(
function()
if __resetflag == true then f:reset(); __resetflag = false; end
x,y = f:getBatch()
return x,y
end,
function(x,y)
-- do some stuff and trigger conditionMet = true if met
end
)
if conditionMet == true break end
end
end
Related
Ok, i'm really bad at coding. I'm especially new to GODOT and am trying to make a 2d game. I've been able to set cant_move to false when dialog is playing, the problem I'm having is making cant_move true again. I don't even know where to put done = true on the dialog script (I kinda just put it in a random place and hoped it would work). Here is my dog-shit code. (the solution is probably easy im just really dumb)
npc script
`extends Area2D
var done = true
func _ready():
Global.npc1 = self
func _exit_tree():
Global.npc1 = null
var can_interact = false
const DIALOG = preload("res://dialoguebox.tscn")
func _physics_process(delta):
$AnimatedSprite.play()
func diaplay():
if done == false:
Global.player.can_move = false
print("test")
if done == true:
print("test2")
can_interact = false
Global.player.can_move = true
func _on_Area2D_body_entered(body):
if body.name == "player":
$Label.visible = true
can_interact = true
func _on_Area2D_body_exited(body):
if body.name == "player":
$Label.visible = false
can_interact = false
func _input(event):
if Input.is_key_pressed(KEY_E) and can_interact == true:
done = false
diaplay()
$Label.visible = false
var dialog = DIALOG.instance()
get_parent().add_child(dialog)
dialog.position = $Position2D.global_position
dialog script
extends Control
var dialog = [
'sampletext',
'sampletext2',
]
var done = false
var dialog_index = 0
var finished = false
func _ready():
load_dialog()
Global.DialogBox = self
func _exit_tree():
Global.DialogBox = null
func _physics_process(delta):
$"Ind".visible = finished
if Input.is_action_just_pressed("ui_accept"):
load_dialog()
func load_dialog():
if dialog_index < dialog.size():
finished = false
$RichTextLabel.bbcode_text = dialog[dialog_index]
$RichTextLabel.percent_visible = 0
$Tween.interpolate_property(
$RichTextLabel, "percent_visible", 0, 1, 1,
Tween.TRANS_LINEAR, Tween.EASE_IN_OUT
)
$Tween.start()
if dialog_index >= 0:
Global.npc1.done = true
else:
queue_free()
done = true
dialog_index += 1
func _on_Tween_tween_completed(object, key):
finished = true
If I understand correctly, you are opening the UI with this code:
var dialog = DIALOG.instance()
get_parent().add_child(dialog)
dialog.position = $Position2D.global_position
So add the instruction to make can_move false there (Global.player.can_move = false).
And apparently it is all done here:
queue_free()
That is, the UI is removing it self. When the UI removes itself, it exits the scene tree, we are going to take advantage of that. Connect the tree_exited of the UI to a func that sets can_move true again:
Global.player.can_move = false
var dialog = DIALOG.instance()
dialog.position = $Position2D.global_position
dialog.connect("tree_exited", self, "dialog_exited")
get_parent().add_child(dialog)
func dialog_exited() -> void:
Global.player.can_move = true
That should do.
Alternatively you could create and emit a signal to notify when the player can move again. Refer to the documentation about signals.
Addendum
I think I got what else is not working. Look at load_dialog:
func load_dialog():
if dialog_index < dialog.size():
# ... some code ...
if dialog_index >= 0:
Global.npc1.done = true
else:
queue_free()
done = true
dialog_index += 1
The first check (dialog_index < dialog.size()) is if there is more dialog text. If there isn't then it is done. So change it to this:
func load_dialog():
if dialog_index < dialog.size():
# … some code …
else:
Global.npc1.done = true
queue_free()
done = true
dialog_index += 1
I hope that makes sense.
You also mention you got an error in Global.player.can_move = true, I suppose that happened with closing the game, that code ran, and Global.player was no longer valid.
Regardless of the situation, you can check if the player is valid:
var player = Global.player
if is_instance_valid(player):
player.can_move = true
I don't have enough rep to comment but I just want to add that you have two different done variables. One in NPC and another in Dialog. You set them true here:
if dialog_index >= 0:
Global.npc1.done = true
else:
queue_free()
done = true
I think the problem might also be that dialog's done is never set true again. But I'm a noob too and Theraot always give good advice so check his answer again.
In fact he already solved this problem:
if dialog_index < dialog.size():
# … some code …
else:
Global.npc1.done = true
queue_free()
done = true
dialog_index += 1
For clarity i would try to use only one done variable, probably connecting the scrips with signals also as Theraot said.
I was playing around with recursive and create this.
ABBB runs OK, get true
BABB runs OK, get true
BBAB runs OK, get true
BBBA does not run properly, get false
This part of the function runs properly, but when exit function is called the line jumps to the last end if line of the code. When I f8 through the code it jumps back and forth three times. It is almost as if it is compiling x3 the if loop instead of exiting the function.
OK this works. Thank you all.
Function practieRecursive(userstring, UserStringIndex) As Boolean
UserStringIndex = UserStringIndex + 1
If CInt(UserStringIndex) > Len(userstring) Then
practieRecursive = False
Exit Function
ElseIf Mid(userstring, UserStringIndex, 1) = "A" Then
practieRecursive = True
Debug.Print practieRecursive
Exit Function
Else
practieRecursive = practieRecursive(userstring, UserStringIndex)
Exit Function
End If
Debug.Print practieRecursive
End Function
You're attempting Mid(userstring, UserStringIndex, 1) = "A" before checking CInt(UserStringIndex) = Len(userstring). Reorder your checks.
Function practieRecursive(userstring, UserStringIndex) As Boolean
UserStringIndex = UserStringIndex + 1
If CInt(UserStringIndex) = Len(userstring) Then
practieRecursive = False
Exit Function
elseIf Mid(userstring, UserStringIndex, 1) = "A" Then
Stop
practieRecursive = True
Exit Function
Else
Call practieRecursive(userstring, UserStringIndex)
End If
End Function
I'm writing extension/plugin for some app.
In its documentation it's said, that there are 2 threads for plugin:
- "main thread" where all business logic must live
- "callback thread" where application invokes callbacks with predefined names by events, these callbacks must not do complicated things and return as soon as possible
documentation is not very clear so it's possible that callbacks are invoked not from one thread but from many threads.
I've wrote dummy mutex, that works like that:
Mutex = class {
_lock = function(self, owner)
assert(owner, 'owner must be set')
local ts = Timestamp.get()
local key = tostring(owner) .. ' ' .. tostring(ts)
self[key] = ts
for k, v in pairs(self) do
if k ~= key and v <= ts then
self[key] = nil
return false
end
end
return key
end,
lock = function(self, owner, wait)
local wait = wait or 0.01
local k
repeat
k = self:_lock(owner)
if k then return k else sleep(wait) end
until k
end,
unlock = function(self, key)
self[key] = nil
end
}
and use it for making thread safe queue like this:
ThreadSafeQueue = class {
new = function(cls)
return getmetatable(cls).new(cls, {
mx_queue = Mutex:new(),
mx_push = Mutex:new(),
})
end,
pop = function(self)
local lock_queue = self.mx_queue:lock(self)
local val
if #self then
val = table.remove(self, 1)
else
val = nil
end
self.mx_queue:unlock(lock_queue)
return val
end,
push = function(self, val)
if val == nil then return end
-- don't `push()` from few threads at the same time
local lock_push = self.mx_push:lock(val)
-- don't `pop()` when `push()` and `push()` when `pop()`
local lock_queue = self.mx_queue:lock(self)
self[#self + 1] = val
self.mx_queue:unlock(lock_queue)
self.mx_push:unlock(lock_push)
end
}
class here is helper that returns object with prototype lookups and :new() method which sets metatable.
Main problem is that I'm not sure what pairs() does.
- If original table will be modified while it's being iterated, will this loop return at least old state?
- Is it possible that some k, v will not be iterated in such case?
Other problem is that application I'm writing for is really black box and I'm not even sure on which os it will run (Win, Mac, Linux).
Everything that I know 100% that I have threads and socket module.
Could you review provided code?
Will it work?
Is there any other possibilities for mutex.
May be socket will give something?
option for socket:
try to create socket, if success, then mutex locked, else - wait it for close
local Mutex = class {
identities = {},
new = function(cls, identity)
assert(not cls.identities[identity])
local inst = getmetatable(cls).new(cls, {
port = identity,
server = nil
})
cls.identities[identity] = inst
return inst
end,
lock = function(self, wait)
local wait = wait or 0.01
local server
local ts = Timestamp.get()
repeat
server = socket.bind("*", self.port)
if server then
self.server = server
return true
else
sleep(wait)
end
assert(Timestamp.get() - ts < 3, 'deadlock')
until server
end,
unlock = function(self)
self.server:close()
self.server = nil
end
}
This is my code:
serialPort = 'COM3';
s = serial(serialPort,'BaudRate',9600);
if (s.Status == 'closed')
s.BytesAvailableFcnMode = 'byte';
s.BytesAvailableFcnCount = 200;
s.BytesAvailableFcn = #Serial_OnDataReceived;
fopen(s);
end
This is the CallBack function
function Serial_OnDataReceived(obj,event)
global s;
global i;
global endCheck;
global yVals;
global xVals;
if (s.Status == 'open')
while s.BytesAvailable > 0 && endCheck ~= '1',
data = str2num(fgetl(s));
dlmwrite ('SensorsReading.csv', data, '-append');
yVals = circshift(yVals,-1);
yVals(end) = data(3);
xVals = circshift(xVals,-1);
i = i + 0.0125;
xVals(end) = i;
end
figure(1);
plot(xVals,yVals);
end
end
Right after the FOPEN function, I get this Warning:
The BytesAvailableFcn is being disabled. To enable the callback property
either connect to the hardware with FOPEN or set the BytesAvailableFcn property.
Does the logic that happens in the callback function Serial_OnDataReceived run on a different thread?
Is there a way to pass parameters to the function? I want to modify an array in the main script from the callback function, which is in a different file. What's the best way to do so?
I am also trying to plot the values when they're updated to show some kind of dynamic animation.
I am not sure about what is generating the warning, but to answer your other question (how to pass parameter to the callback and how to update the plot), a better way to go would be to prepare your plot outside of the callback, then pass the handle to the callback for update only.
nPointsInFigure = 10 ; %// number of "sliding points" in your figure
step = 0.0125 ; %// X points spacing
xVals = linspace(-(nPointsInFigure-1)*step,0,nPointsInFigure) ; %// prepare empty data for the plot
yVals = NaN(nPointsInFigure,1) ;
figure(1) ;
hp = plot( xVals , yVals ) ; %// Generate the plot (with empty data) it will be passed to the callback.
serialPort = 'COM3';
s = serial(serialPort,'BaudRate',9600);
if (s.Status == 'closed')
s.BytesAvailableFcnMode = 'byte';
s.BytesAvailableFcnCount = 200;
s.BytesAvailableFcn = {#Serial_OnDataReceived,hp,step} ; %// note how the parameters are passed to the callback
fopen(s);
end
Your callback will become:
function Serial_OnDataReceived(obj,event,hp,step)
global endCheck; %// I don't know how you use that so I could not get rid of it.
xVals = get(hp,'XData') ; %// retrieve the X values from the plot
yVals = get(hp,'YData') ; %// retrieve the Y values from the plot
while obj.BytesAvailable > 0 && endCheck ~= '1',
data = str2num(fgetl(s));
dlmwrite ('SensorsReading.csv', data, '-append');
yVals = circshift(yVals,-1);
yVals(end) = data(3);
xVals = circshift(xVals,-1);
xVals(end) = xVals(end-1) + step ;
end
set( hp , 'XData',xVals , 'YData',yVals ) ; %// update the plot with the new values
Also note: (1) You don't need to check for the state open/close of the serial port within the callback function. If the event was triggered it means the port was open. (2) you don't need to declare s as global, the obj parameter is actually the serial object itself.
If the suggestion from Hoki does not work, try using a timer.
% The following line is useful for debugging
mytimerCallback = #(~, ~) disp('Caught error For Tenzo Timer');
if isempty(timerXbee)
timerXbee = timer('ExecutionMode','FixedRate','Period',0.1,...
'TimerFcn',{#storeDataFromSerial},'ErrorFcn', mytimerCallback);
try
start(timerXbee);
catch
disp('Timer Xbee');
disp '******** InstrumentSubscription ERROR *********'
disp (exception.message);
disp '***********************************************'
end
end
% If you are using a polling approach, request data
sendRequest(cmd);
connectionRequested = true;
Then implement the timer function that will be called every period
function storeDataFromSerial(~,~,~)
while (get(xbee, 'BytesAvailable')~=0)
serialProtocol();
end
end
When you want to disconnect the device and close the communication don't forget to stop the timer with
stop(timerXbee)
Fresh to the Matlab, not so familiar with coding and programing in MatLab.
function fucx()
for i = 1:3
for j = 1:3
for k = 1:3
try
%MainFuc()
%TimerFuc()
time = cputime;
time = cputime-time;
a = timer;
set (a, 'executionMode', 'fixedRate')
set (a,'timerfcn','disp(time)')
start(a)
timeStop = time;
if (timeStop>60) % in seconds
disp('RunOutOfTime: Program terminated');
stop(a)
break;
end;
catch
%%Err()
end
end
end
end
end
Thanks a lot for any help.
%%Update%%
I see the recommended answer as below. I've tried this one.
start = tic;
for i=1:1000000
if (mod(i,1000)==0)
if (toc(start) > 2) % here, 2 seconds
error('Took toooo loooong');
end
end
end
The thing I want to assure is that the timer or tic function running in parallel to the MainFuc() and know when to stop the loop.
You should use the "tic" and "toc" functions from matlab, see the documentation here Matlab tic function.
When you call "tic", the timer restarts, and every time you call "toc" it gives you the time in seconds since the last "tic". Then if you call "tic" another time, the timer will restart.
Here is the code you need.
a = 0;
for i = 1:3
for j = 1:3
tic;
for k = 1:10^7
try
%MainFuc()
a = a + 1;
catch
%%Err()
end
%TimerFuc()
time = toc;
if (time>2) % in seconds
disp('RunOutOfTime: Program terminated');
break;
end;
end
end
end