digitalmars.D.learn - Strange multithreading error
- Ruby The Roobster (486/488) Oct 29 2021 I am currently writing a test program for a collision function,
- Steven Schveighoffer (8/16) Oct 29 2021 In order for a member function to be called on a shared object,
- Ruby The Roobster (3/21) Oct 29 2021 Thank you, this solved my problem.
I am currently writing a test program for a collision function, that involves multithreading so I can simultaneously check for collisions and move a skeleton at the same time. Because of this, I had to use ```shared``` objects. The specific objects I was using were declared in a file called "skeleton.d." In a function I wrote for moving the skeletons, it uses operator overloading, which produces the following output: ```d physics.d(85): Error: none of the `opOpAssign` overloads of `Point` are callable for `j` of type `shared(Point)` physics.d(87): Error: none of the `opOpAssign` overloads of `Point` are callable for `k.start` of type `shared(Point)` physics.d(88): Error: none of the `opOpAssign` overloads of `Point` are callable for `k.stop` of type `shared(Point)` physics.d(90): Error: none of the `opOpAssign` overloads of `Point` are callable for `i.center` of type `shared(Point)` physics.d(92): Error: none of the `opOpAssign` overloads of `Point` are callable for `tomove.center` of type `shared(Point)` physics.d(112): Error: none of the `opOpAssign` overloads of `Point` are callable for `k` of type `shared(Point)` physics.d(114): Error: none of the `opOpAssign` overloads of `Point` are callable for `j.start` of type `shared(Point)` physics.d(115): Error: none of the `opOpAssign` overloads of `Point` are callable for `j.stop` of type `shared(Point)` physics.d(117): Error: none of the `opOpAssign` overloads of `Point` are callable for `i.center` of type `shared(Point)` physics.d(119): Error: none of the `opOpAssign` overloads of `Point` are callable for `ori.center` of type `shared(Point)` physics.d(120): Error: none of the overloads of `opAssign` are callable using a `shared` object skeleton.d(81): Candidates are: `skeleton.Skeleton.opAssign(Skeleton rhs)` skeleton.d(88): `skeleton.Skeleton.opAssign(shared(Skeleton) rhs)` physics.d(136): Error: mixin `physics.move.__mov__general__!"n"` error instantiating ``` This is clearly wrong, as type ```Point``` is not the same as type ```Skeleton```. For reference, here are the files: test.d: ```d import physics; void main() { Skeleton cube; Face[] cubefaces; cubefaces.length = 1; cubefaces[0].lines ~= Line([Point(0,0.25,0), Point(0,0.5,0), Point(0,0.75,0)], Point(0,0,0), Point(0,1,0)); cubefaces[0].lines ~= Line([Point(0.25,0,0), Point(0.5,0,0), Point(0.75,0,0)], Point(0,0,0), Point(1,0,0)); cubefaces[0].lines ~= Line([Point(1,0.25,0), Point(1,0.5,0), Point(1,0.75, 0)], Point(1,0,0), Point(1,1,0)); cubefaces[0].lines ~= Line([Point(0.25,1,0), Point(0.5,1,0), Point(0.75,1,0)], Point(0,1,0), Point(1,1,0)); cubefaces[0].center = Point(0.5,0.5,0); cube.faces = cubefaces.dup; cube.center = Point(0.5,0.5,0); auto cube2 = cube; move(Point(99,0,0), 0, cast(shared(Skeleton))cube, 99); import std.stdio; import std.concurrency; spawn(&test1, cast(shared(Skeleton))cube2, cast(shared(Skeleton))cube); spawn(&move,Point(-99,0,0), 5, cast(shared(Skeleton))cube, 1); bool b = receiveOnly!bool; writeln(b); } void test1(shared ref Skeleton cube2, shared ref Skeleton cube) { import std.concurrency; if(detectCollision(cast(shared(Skeleton[]))[cube2], cast(shared(Skeleton))cube, real.infinity)) send(ownerTid(), true); } ``` skeleton.d: ```d /*skeleton.d by Ruby The Roobster*/ /*Version 1.0 Release*/ /*Module for representing skeletons in the D Programming Language 2.0*/ /*This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.*/ /** Copyright: 2021, Ruby The Roobster*/ /**Author: Ruby The Roobster, michaeleverestc79 gmail.com*/ /**Date: October 1, 2021*/ /** License: GPL-3.0*/ module skeleton; /**Struct for representing a point.*/ public struct Point { //Point structure... ///Point.x is the 'x' coordinate of the point. real x; ///Point.y is the 'y' coordinate of the point. real y; ///Point.z is the 'z' coordinate of the point. real z; this(real x, real y, real z) { this.x = x; this.y = y; this.z = z; } void opAssign(Point rhs) { this.x = rhs.x; this.y = rhs.y; this.z = rhs.z; } void opAssign(shared Point rhs) { this.x = rhs.x; this.y = rhs.y; this.z = rhs.z; } void opOpAssign(string op)(Point rhs) { mixin("this.x " ~ op ~ "= rhs.x;"); mixin("this.y " ~ op ~ "= rhs.y;"); mixin("this.z " ~ op ~ "= rhs.z;"); } void opOpAssign(string op)(shared(Point) rhs) { mixin("this.x " ~ op ~ "= rhs.x;"); mixin("this.y " ~ op ~ "= rhs.y;"); mixin("this.z " ~ op ~ "= rhs.z;"); } } /**Struct for representing a face of a skeleton that is made out of lines.*/ public struct Face { //Face(of a 3D shape) structure... ///Face.lines is an array of all the lines that connect to form the face. Line[] lines; ///Face.center is the center point of the face. Point center; void opAssign(Face rhs) { this.lines.length = rhs.lines.length; foreach(i;0 .. this.lines.length) { this.lines[i] = rhs.lines[i]; } } void opAssign(shared Face rhs) { this.lines.length = rhs.lines.length; foreach(i;0 .. this.lines.length) { this.lines[i] = rhs.lines[i]; } } } /**Struct for representing a 3D skeleton.*/ public struct Skeleton { //Skeleton of a 3D structure... ///Skeleton.faces is an array of the faces that make up the Skeleton. Face[] faces; ///Skeleton.center is the center point of the skeleton. Point center; void opAssign(Skeleton rhs) { this.faces.length = rhs.faces.length; foreach(i;0 .. this.faces.length) { this.faces[i] = rhs.faces[i]; } this.center = rhs.center; } void opAssign(shared Skeleton rhs) { this.faces.length = rhs.faces.length; foreach(i;0 .. this.faces.length) { this.faces[i] = rhs.faces[i]; } this.center = rhs.center; } } /**Struct for representing a line composed of at least a starting point and an end point. *Notes: *This struct doesn't check to make sure that the line made is an actual line and assumes the user knows what they are doing. */ public struct Line { //Line struct... ///Line.mid_points is an array containing all of the points that are neither start nor end points. Point[] mid_points; ///Line.start is the start point of the line. Point start; ///Line.end is the end point of the line. Point stop; void opAssign(Line rhs) { this.start = rhs.start; this.stop = rhs.stop; this.mid_points.length = rhs.mid_points.length; foreach(i;0 .. this.mid_points.length) { this.mid_points[i] = rhs.mid_points[i]; } } void opAssign(shared Line rhs) { this.start = rhs.start; this.stop = rhs.stop; this.mid_points.length = rhs.mid_points.length; foreach(i;0 .. this.mid_points.length) { this.mid_points[i] = rhs.mid_points[i]; } } } ``` and finally, physiscs.d: ```d /*physics.d by Ruby The Roobster*/ /*Version 0.35 testing*/ /*Module for basic physics in the D Programming Language 2.0*/ /*This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.*/ /** Copyright: 2021, Ruby The Roobster*/ /**Author: Ruby The Roobster, michaeleverestc79 gmail.com*/ /**Date: October 27, 2021*/ /** License: GPL-3.0*/ module physics; public import skeleton; package mixin template __mov__general__(string func) { void __mov__general__(real accdec = 0) { import core.thread; Point moveby; bool b = false; auto ori = tomove; debug import std.stdio : writeln; if(speed > 1 || speed < -1) { moveby.x = moveto.x / speed; moveby.y = moveto.y / speed; moveby.z = moveto.z / speed; b = true; } else { moveby.x = moveto.x * speed; moveby.y = moveto.y * speed; moveby.z = moveto.z * speed; } while(!((tomove.center.x > moveto.x && moveto.x > 0) ^ (tomove.center.x < moveto.x && moveto.x < 0))) { static if(func == "a") { speed += accdec; if(b) { moveby.x = moveto.x / speed; moveby.y = moveto.y / speed; moveby.z = moveto.z / speed; } else { moveby.x = moveto.x * speed; moveby.y = moveto.y * speed; moveby.z = moveto.z * speed; } } else static if(func == "d") { speed -= accdec; if(b) { moveby.x = moveto.x / speed; moveby.y = moveto.y / speed; moveby.z = moveto.z / speed; } else { moveby.x = moveto.x * speed; moveby.y = moveto.y * speed; moveby.z = moveto.z * speed; } } foreach(i;tomove.faces) { foreach(k;i.lines) { foreach(j;k.mid_points) { j += moveby; } k.start += moveby; k.stop += moveby; } i.center += moveby; } tomove.center += moveby; Thread.sleep(dur!"msecs"(tbf)); static if(func == "a") { speed += accdec; } else static if(func == "d") { speed -= accdec; } else { } } foreach(i;ori.faces) { foreach(j;i.lines) { foreach(k;j.mid_points) { k += moveto; } j.start += moveto; j.stop += moveto; } i.center += moveto; } ori.center += moveto; tomove = ori; } } /** * move moves all the points in a skeleton to a specified point with a specified time gap between moving the points. * Params: * moveto = A point specifying the total amount to move along each axis. * tbf = The time in miliseconds between 'frames'(a frame is one section of moving points before waiting a bit). This gives an illusion of continuous motion. * tomove = The skeleton being moved. * speed = The speed at which to move the points. * Returns: * none */ pragma(inline, true) public void move(Point moveto, uint tbf, ref shared Skeleton tomove, real speed) { mixin __mov__general__!"n"; __mov__general__(); } /** * accMove moves all the points in a skeleton to a specified point with a specified time gap between movements all while accelerating the speed. * Params: * moveto = A point specifying the total amount to move along each axis. * tbf = The time in miliseconds between 'frames'(a frame is one section of moving points before waiting a bit). This gives an illusion of continuous motion. * tomove = The skeleton being moved. * speed = The original speed at which the skeleton moves. * accdec = The amount to increment the speed by each frame. */ pragma(inline, true) public void accMove(Point moveto, uint tbf, shared ref Skeleton tomove, real speed, real accdec = 0) { mixin __mov__general__!"a"; __mov__general__(accdec); } /** * decMove moves all the points in a skeleton to a specified point with a specified time gap between movements all while deaccelerating the speed. * Params: * moveto = A point specifying the total amount to move along each axis. * tbf = The time in miliseconds between 'frames'(a frame is one section of moving points before waiting a bit). This gives an illusion of continuous motion. * tomove = The skeleton being moved. * speed = The original speed at which the skeleton moves. * accdec = The amount to decrement the speed by each frame. */ pragma(inline) public void decMove(Point moveto, uint tbf, shared ref Skeleton tomove, real speed, real accdec = 0) { mixin __mov__general__!"d"; __mov__general__(accdec); } public bool detectCollision(shared Skeleton[] towatch, shared Skeleton skele, real time = 0) in { auto a = cast(ulong)time; assert(a == time || time == real.infinity,"Parameter time must always be a whole number or infinity!"); } do { mixin find!(["x", "y", "z"]); import std.datetime.stopwatch; auto sw = StopWatch(AutoStart.no); sw.start(); scope(exit) sw.stop(); while(sw.peek.total!"msecs" <= time || time == real.inf) { foreach(i;towatch) { foreach(j;i.faces) { foreach(k;j.lines) { foreach(l;k.mid_points) { foreach(m;skele.faces) { foreach(n;m.lines) { for(uint o; o < n.mid_points.length+1; o++) { if(switcho(l)) return true; if(switcho(k.start)) return true; if(switcho(k.stop)) return true; } } } } } } } } return false; } package mixin template find(string[] tofind) { static foreach(i; tofind) { mixin("real high" ~ i ~ ";"); mixin("real low" ~ i ~ ";"); } void find(Point[2] tof) { static foreach(i; tofind) { mixin("high" ~ i ~ " = tof[0]." ~ i ~ " >= tof[1]." ~ i ~ " ? tof[0]." ~ i ~ " : tof[1]." ~ i ~ ";"); mixin("low" ~ i ~ " = tof[0]." ~ i ~ " <= tof[1]." ~ i ~ " ? tof[0]." ~ i ~ " : tof[1]." ~ i ~ ";"); } } } package pragma(inline, true) bool switcho(Point toswitch) { switch(o) { default: if(o == n.mid_points.length) { find([n.mid_points[o-1], n.stop]); } else { find([n.mid_points[o-1], n.mid_points[o]]); } if(toswitch.x <= highx && toswitch.x >= lowx && toswitch.y <= highy && toswitch.y >= lowy && toswitch.z <= highz && toswitch.z= lowz){ return true; } break; case 0: find([n.mid_points.start, n.mid_points[o]]); if(toswitch.x <= highx && toswitch.x >= lowx && toswitch.y <= highy && toswitch.y >= lowy && toswitch.z <= highz && toswitch.z= lowz){ return true; } } } ``` Can anyone explain why it can't find the correct function? Thanks in advance.
Oct 29 2021
On Friday, 29 October 2021 at 22:02:53 UTC, Ruby The Roobster wrote:I am currently writing a test program for a collision function, that involves multithreading so I can simultaneously check for collisions and move a skeleton at the same time. Because of this, I had to use ```shared``` objects. The specific objects I was using were declared in a file called "skeleton.d." In a function I wrote for moving the skeletons, it uses operator overloading, which produces the following output: [...]In order for a member function to be called on a shared object, the function has to be marked shared. Typically done like ```d void opAssign(shared Skeleton rhs) shared ``` -Steve
Oct 29 2021
On Friday, 29 October 2021 at 23:32:38 UTC, Steven Schveighoffer wrote:On Friday, 29 October 2021 at 22:02:53 UTC, Ruby The Roobster wrote:Thank you, this solved my problem.I am currently writing a test program for a collision function, that involves multithreading so I can simultaneously check for collisions and move a skeleton at the same time. Because of this, I had to use ```shared``` objects. The specific objects I was using were declared in a file called "skeleton.d." In a function I wrote for moving the skeletons, it uses operator overloading, which produces the following output: [...]In order for a member function to be called on a shared object, the function has to be marked shared. Typically done like ```d void opAssign(shared Skeleton rhs) shared ``` -Steve
Oct 29 2021