Jump to content

  • Log In with Google      Sign In   
  • Create Account

Interested in a FREE copy of HTML5 game maker Construct 2?

We'll be giving away three Personal Edition licences in next Tuesday's GDNet Direct email newsletter!

Sign up from the right-hand sidebar on our homepage and read Tuesday's newsletter for details!


Trienco

Member Since 22 Aug 2001
Offline Last Active Yesterday, 11:05 PM

#5098863 How do I use multithreading?

Posted by Trienco on 04 October 2013 - 10:29 PM

			std::thread helper1(GenerateDistanceList,this);
			helper1.detach();

 

Uhm... so now that you just went ahead and detached your thread, how are you ever going to find out if the thread is actually finished before you just cross your fingers and try to use the new star system?

 

When it comes to multi-threading, you can't just go and randomly make assumptions like "I'm sure the generation will be done in time". I've seen weird situation where threads wouldn't get to run for several seconds. At the very least, you should make sure to call join() before trying to enter the new system. That means you can't just detach and hope for the best. Which means you need to start thinking about who should own the thread object, because a function local variable won't do.




#5097573 include guards for large projects

Posted by Trienco on 29 September 2013 - 02:40 AM

pragma once is actually something I seem to have forgotten to mention. Unless one has to worry about obscure or outdated compilers, I'd always prefer that over the ifndef/define mess. Not just for potential optimizations, but because it's also less error prone in a copy/paste-happy environment (forget to update the include guard and figure out where all the weird errors are coming from).




#5097562 space wars

Posted by Trienco on 29 September 2013 - 12:54 AM

 

So the order of transforms of opengl is actually resversed.

 

 

Rather than thinking backwards, I'd prefer to think in terms of object space, which means that everything in OpenGL is perfectly logical and forward. All transformations are based on your current local coordinate system. A rotation will obviously rotate your coordinate system. x might not align with the global x anymore, but it will always be your objects "right". It also means that all rotations will always happen around your local origin, which also causes a lot less headache than trying to rotate an object around itself from a "world perspective".

 

Unless dealing with "outside influence" on your object, thinking in local coordinates is almost always more convenient and easier to reason about. It also means that nothing is actually happening "backwards".




#5097392 include guards for large projects

Posted by Trienco on 28 September 2013 - 12:22 AM

Forward declarations shouldn't be your last straw if nothing else helps, they should be your default whenever your header only uses pointers or references to something. You should always minimize the includes in header files, not only because of the mess you currently seem to find yourself in, but also because a huge web of includes will result in every source file being ridiculously huge and bloated after the preprocessor is done with it and make compilation take forever.

 

Also, since "include" is nothing but "copy/paste the file content right here", your double and triple checking is redundant, messy and in a best case scenario saves a few microseconds for the file access on any subsequent inclusion attempt.

 

You're drowning in a dependency mess and are flailing to stay above water. The solution isn't to learn how to swim, but to get out of the water. Object and sprite should be a very straight forward one-way dependency, so the question to ask is: why is object.h directly or indirectly including sprite.h? No amount of inclusions guards can fix circular includes.




#5096330 C++ Optimization week!

Posted by Trienco on 23 September 2013 - 10:17 PM

Make sure you're using all cores, ie. in VS check the project settings. C/C++ |General | Multi-processor compilation should be enabled. When using make, be sure to use -j <x> to run up to x jobs in parallel.

 

I noticed that Clang is a lot faster when using precompiled headers compared to GCC (almost as fast as VC++).

 

And as mentioned before, always be aware of your includes, avoid includes in header files as much as possible, consider using the forward declaration headers for some standard libraries, forward declare your own classes if possible, etc. etc. Once that doesn't help anymore, look into precompiled headers (especially if you use the standard library and/boost almost everywhere).

 

With a few tricks I could get a verification build from over 4min down to a little over 10s (with VC++). Disable compiler optimization, disable debug info, use precompiled headers and forward declarations, etc.  Interestingly the difference with GCC was about a zero and that already took twice as long before. Clang on the other hand would go down to around 20s.




#5095865 adventure dungeon game

Posted by Trienco on 21 September 2013 - 11:37 PM


int x=0,y=0,w=4,attack=0,hp=6;//global variables

 

They are declared inside main(), how are they global? Maybe they "feel" global, because you dumped your whole program into a single function, but that's not the same thing.

 


cout << "***Welcome to Adventure***";//welcome text

 

This is a prime example for useless comments that only exist because someone said "you need to comment more".

 


for (int i=0; i<9; i++)//draw grid

 

I was wondering how many times you would copy/paste the same comment without eventually realizing that this code shouldn't be commented, but get its own function.

 

 

Comments should only be used where necessary. Prefer writing clean and readable code with decent names for variables and functions. Which means, don't be lazy and abbreviate the hell out of everything, keep functions short and have them do ONE thing, avoid confusion (don't use i and j as loop variables or any other combination of letters that look alike).

 

If you have a piece of code and feel the need to put a comment over it saying "this block does x", put it in a function and call it "x".

 

Comments are the last thing anyone ever updates, they are frequently copy/pasted along with the code and it's usually less than a month before they turn into a confusing mess of lies and deceit. Write code that speaks for itself and doesn't need comments in the first place.

 

Use comments where explanations are required or a chunk of code is impossible to quickly look at and understand what it's doing. "Find shortest path using A* (<link to more info about A*)" would be a helpful comment. "Assign sum of x and y to variable a" on the other hand is nothing but noise that actually makes it harder to read the code (seriously, if somebody needs you to explain what a=x+y does, they probably shouldn't be looking at any kind of source code in the first place).

 

Frankly, nothing I see in your code needs to be commented, because it's about as trivial and straight forward as it gets. Better names, clean formatting and at least an attempt at well structured code would make any kind of comment superfluous.

 

Get a book like "Clean Code", ignore the dogmatic parts and rather than taking everything as "how it always must be", read it as "what you should strive for within reasonable limits".




#5095352 Design thoughts for compatible classes with different variable sizes?

Posted by Trienco on 19 September 2013 - 10:33 PM

If performance isn't an issue, why not add explicit casts between the classes? All operations are automatically compatible and by requiring explicit casting, the code will always highlight locations where you need to pay attention to type sizes.




#5092602 c++11 Multithreading not working! Please help!

Posted by Trienco on 08 September 2013 - 10:16 PM

So basically you ignored everyone trying to tell you that your code is fundamentally wrong in using separate mutexes (which completely breaks the whole notify/wait mechanism) and instead added your own busy waiting loop, a lot of Sleeps and are now spamming notifications, which have become kind of pointless anyway?

 

The idea is to lock the (common) mutex and check for the condition before you start waiting (in a loop, because of spurious wake ups). Locking the mutex and using the same mutex for one condition is important, else you might get the notify exactly between checking and waiting, which would again result in waiting forever. Why is this condition not part of the condition variable? Because it isn't always a simple bool that is directly tied to it. The condition can (and often is) something like "!queue.empty()".

 

Besides, the idea of notify_one is that exactly one waiting thread will wake up. By spamming notify_one, you could as well rename it to notify_a_bunch.




#5090523 multi-thread

Posted by Trienco on 30 August 2013 - 10:57 PM

I was somewhat hoping the old "let's put each module in a separate thread"-approach has died out a while ago, when developers realized that having all these threads constantly compete for the same resources is a messy nightmare of synchronization and race condition bugs. Unless you make sure that all the modules working in parallel only read the same data. Alternatives usually involve either a lot of copying or a lot of locking. Don't be surprised if the overhead ends up making the whole thing pointless.

 

A first step is to simply use concepts like parallel_for to split up one huge chunk of work to be processed in parallel (note: make sure each element can be processed independently of others). After that, look into task based parallelism. Intel's TBB library and especially its documentation might be a good place to start.




#5090328 using detours 3.0 crash

Posted by Trienco on 30 August 2013 - 02:32 AM

Isn't GetProcAddress a function? Why are you handling it as a null terminated string? The bigger surprise is that it's not already crashing the first time, but you're probably lucky to have a zero on the stack nearby. Output pointers as %p, not as string.




#5089426 passing std::shared_ptr to a function?

Posted by Trienco on 27 August 2013 - 01:54 AM

And yet the fact that operator-> is automatically called recursively until it returns an actual pointer type is occasionally used to implement special behavior or convenient helper functions by using wrapper objects that implement it. It's often the easiest way to keep the calling code clean and blissfully ignorant of implementation details. Try implementing a special proxy on top of a basic proxy to some generic object without exploiting operator->.

 

Basically, the question is: what happened to old-fashioned ways to mark members like 'mMember' or 'member_' that don't have the potential for obscure side effects?

 

There is no ambiguity for functions either, as a function is either a member, global or called through some other object. Global functions should be in a namespace and "using namespace everything" is often preferring laziness over clear code. So suddenly foo() is obviously a member function, as otherwise it would be something like std::foo() or ::foo().




#5089417 Convert C function args to CPP function args

Posted by Trienco on 27 August 2013 - 01:20 AM

Fixing all the existing code might be a bit tedious, but at least all new code should be const correct right away. If the function will not modify the string behind the pointer, it should clearly say so by using const. The most critical reason is that otherwise the function will be incompatible with C++ code that uses std::string (.c_str() returns a const
char*). Personal highlight: a coworker actually adding a comment that his function will not modify the string instead of just making the darn thing const.

 

If the point is to C++ify the code, I'd go one step further and use std::string as much as possible (functions then take 'const string&', rather than 'const char*').




#5084310 Duplicated Code

Posted by Trienco on 08 August 2013 - 10:26 PM

Ask yourself this: if instead of describing forms (which are basically just 90° steps of rotation) you would describe a free rotation, would you go and create 360 bools all called rotated1Degree, rotated2Degree, ...? What if you need half or quarter degree steps? Because that's essentially what you are doing right now, except it hasn't yet reached the point of becoming obviously ridiculous and unmaintainable.

 

In terms of getting the project done: it works, move on.

In terms of practice or better code: consider some of the cleaner approaches mentioned above.

 

How are you doing all the other stuff like drawing? Is there a lot if if-else to pick the right shape? Wouldn't it be easier if the form was a number that also just indexes into an array with the correct shape? Are you checking for consistency (always one and exactly one of them being true)? Basically when you say "mutually exclusive" that should also mean "not stored as multiple bools".




#5078370 Function addresses are not fixed relative to each other?

Posted by Trienco on 16 July 2013 - 10:13 PM

When you cast your function pointers to integers, I'd always preclude that with a static-assertion testing that the size of your function pointer type is smaller or equal to the size of your int type.

 

Of course, if I really have to use printf to output any kind of pointer, I'd just use %p in the first place...




#5078047 Problem with strings

Posted by Trienco on 15 July 2013 - 10:27 PM

Which is why a / should be used as a path separator whenever possible (yes, even on Windows). There are extremely few cases where it won't work.






PARTNERS