Jump to content

  • Log In with Google      Sign In   
  • Create Account

Banner advertising on our site currently available from just $5!

1. Learn about the promo. 2. Sign up for GDNet+. 3. Set up your advert!


Member Since 18 Jan 2008
Offline Last Active Yesterday, 02:13 PM

#5244144 Is using a GUID (Globally Unique Identifier), a good idea for storing rpg ite...

Posted by samoth on Yesterday, 07:42 AM

I would most definitively not use a GUID for that. Why, to what avail?


A GUID has 128 bits and yet is not guaranteed to be unique (the likelihood is compelling, but there is no strict guarantee). Sequential integers take anywhere from 32 to 64 bits and are guaranteed to be unique (until overflow happens). But that's not an issue.


Even if a thousand bosses die every second, and each drops 10 lootable items, that's almost 5 days before a puny 32-bit counter overflows. Loot doesn't stay on the ground for 5 days, and you couldn't store 4 giga-items in memory anyway. You won't live to see a 64-bit integer overflow at that rate.


Further, do you even need the loot to be individual? I say no.


Given your description of being able to pick up an item and do "anything" with it, it's perfectly adaequate to e.g. pick up a "generic template" item and convert that to a unique item as soon as it enters the inventory (or maybe even when it's actually modified!). You can have several different but similar templates with the same human readable name or you can attach both a template plus a modifier to each item if you want some variation (so there exist goblin killing swords +17 and goblin killing swords +18 that you can pick up).


But even if you want every single item to be a fully fledged individual item from the start, using a 64-bit sequentially increasing integer will do. Unless you plan to generate more than 10,000 of them every second for the next 5 million years. Mind you, it might be troublesome having a 5 million year uptime on the server.


Of course, a GUID will "work fine", but whenever the words "many thousands" appear, you usually want to keep stuff as small as possible.

#5243986 Land/Sea ratio from a Heightmap

Posted by samoth on 01 August 2015 - 06:15 AM

Your histogram tells you how often each of the values between 0 and 255 appears in the image/heightmap. What you want is some value so 50% of all the values in your heightmap are below it (and the other 50% are above, obviously). In other words, the index where the sum of all values to the left is equal to 50% of the total number of values.

Thus, you want to know for which index the prefix sumis equal (or very close to) the number of values in the heightmap.


A very easy approach that should do would look somewhat like this:

int get_tuneable(heightmap const& hm, histogram const& histo)
    int threshold = (hm.width * hm.height) / 2;
    int sum = 0;
    for(int i = 0; i <256; ++i)
        if((sum += histo[i]) >= threshold)
            return i;
    // just to be sure
    return i;

I'm almost sure that the fully correct mathematical formulation would be something like "the median of the prefix sum", but finding the median is rather tedious, and building the whole prefix sum is wasteful. While you are summing up the values, it is very easy and straightforward to just break when you have found your value.

#5242966 To use mana or not? (that is the question)

Posted by samoth on 27 July 2015 - 07:42 AM

I like mana rather than vanacian magic because the model strikes me as "more natural". Mixing in cool downs and charging is OK to some extent, but they should not dominate the game.


When I'm going to chop some trees in my garden (OK, nowadays I'm too old for that shit and use a chainsaw, but in the good old days...), I can chop three trees the size of my leg in an afternoon, and dig out one tree's roots. That's because after chopping 3 trees and digging one root, my "mana" is gone, and I'll need a night's rest to restore mana before tackling the next root. It's not because I've prepared only 3 chop-tree-spells and one dig-root-spell. I wouldn't be able to chop down as many as two trees that are twice as thick (nor dig any roots afterwards). I wouldn't be able to dig out two roots in a day either, regardless of how carefully I prepare. That's mana.


In between chopping a tree and the next one, I'll need some 20 minutes of rest because my wrists are hurting from the impact. There's your cooldown. It doesn't dominate, but it sure limits my ability.


Now, after this hard chopping and digging, I decide to go to the swimming pool. Let's say that I can dive 2/3 to the other end of the pool. But if I breathe in deeply a few times, I can dive the whole distance. There you have charge.


In real life, neither charge nor cooldown dominate, but they sure can have a noticeable effect. The only "vanacian" stuff that you encounter in life is when you go to the opera/ballet. You either have two tickets or you don't, and after you used them, they're gone (and it's a pain to replace them).

If you decide that you would rather go to the cinema, that's bad luck for you. Your ballet tickets won't work for that. Neither will they work for paying a dinner.

#5242661 Breaking out of a nested loop

Posted by samoth on 25 July 2015 - 01:38 PM

When something looks like goto and walks like goto and smells like goto, too... why not just use goto?


It's not like goto is inherently evil. Yes, there are holy wars going over it all over the internet (and predating the internet) but so what. Someone on the internet is wrong.


It is just what you're doing! You're doing a jump out of a nested loop, don't pretend you're doing anything different. It's exactly what the assembly that the compiler produces will look like, too. And besides, it's pretty close to the "most obvious, least astonishing" way of doing it.


Given the option of simply returning from the surrounding function, I'd choose that, because it avoids using goto for no reason. But in every other case, I wouldn't try to hide the goto that I'm doing secretly.





Awesome approach. But then again, it's setting up a lambda object (with captures and all) for no good reason. The compiler might optimize that out again, but that isn't granted.

Similar is true for any such construct involving function calls of which you can assume but don't know for sure that the compiler will optimize them away.


That's somewhat going against Sutter/Alexandrescu's rule: Don't pessimize prematurely (that one immediately follows "Don't optimize prematurely"). It's not like you're going to use goto all over the place. There are singular cases where goto is just appropriate, and in these singular cases you can just use it. You can, but you probably shouldn't invest both development time and runtime into making something "better" that is already... well... good.

#5242580 The amount and structure of exception handling in production game code

Posted by samoth on 25 July 2015 - 03:28 AM

What you then DO with said exception is up to you. (crash, exit to desktop, display a placeholder "asset missing" model, etc)
That's just the thing that 90% of all people get wrong about exeptions, though.


If you crash or exit to desktop (maybe with a message "uncaught exception"), then you could just as well not use exceptions at all. Simply call std::terminate, or abort. Nobody cares about being shown an uninformative (...to an end user) message before you find yourself back at the desktop with all your work (or game state) lost. You want that the show goes on.


The entire point of exceptions is that you can do something different from killing the process. You can (possibly, depending on what went wrong) recover from the unexpected situation, and continue running. It might add a 0.5ms overhead to process that exception, and yeah, your game's framerate might drop from 60 to 30 for a frame or two. Get over it. What's important is that the show goes on.


Seeing "asset missing" in the console and having that one tree in this level show as placeholder object or with a grey texture is acceptable. You finish playing that level, save, and then go to Reddit and post a funny comment. Maybe you take the time to send the game makers a note about the missing asset, too.


Getting an "uncaught exception" dialog box 30 seconds before the next save point followed by finding yourself back at the desktop, on the other hand, is an experience of the "What the... Fuuuuuuuck...." kind. This is a user experience that one absolutely wants to avoid.

#5242388 The amount and structure of exception handling in production game code

Posted by samoth on 24 July 2015 - 07:37 AM

This is contrary to the established "best practice" in the industry, but I would actually recommend that you keep using exceptions. Use them, use them wisely, and you will be a very happy person.


Exceptions, like memory allocations and using standard library algorithms, have the problem that there exist implementations that just suck, and as game developer you may find yourself in the situation of having to use one of these. This, and of course the fear of the unknown, is the reason why almost everybody loathes exceptions.


I don't qualify as anything more than a lowly hobbyist
That means you will not be writing code for a platform which only has a crap C++ compiler (simply because it's unaffordable for a private person to acquire the license).


On the other hand, when they don't suck, the advantages of exceptions by far outweight their disadvantages. SEH in particular is nice because it doesn't cost anything as long as nothing is thrown. Your code becomes a lot clearer and more straightforward, and it doesn't cost you.  Excuse me? Executable grows by 10-20 kilobytes for exception tables? Oh please, be real. Nobody complains about executable size exploding (not just 10-20kB) the moment they include iostream.


Also, it can very well be a performance optimization not having to write explicit code that checks for errors (well, you do write that error-checking code, but it's not executed).


Exceptions are a form of flow control. They just are not a form of flow control that you should encounter all the time (it's exception handling, not expection handling).


Which means you should preferrably not see any exceptions at all, but it won't kill you if you see one or two in a cold section. After all, if you weren't ever allowed to see an exception because exceptions are the plague, it would be nonsensical to have that language feature in the first place.


Exceptions (or rather, exeption-safety) can make code a lot more complicated, yes. But they can also make code a lot shorter, easier and easier to understand. Imagine code like this, which you could rightfully consider expection handling (but which I nevertheless deem legitimate due to how much easier it gets):

bool init_stuff( /* param1, param2 */ )
    HANDLE foo, bar, baz;
    if(foo = CreateWhatever())
        if(bar = OpenBlah())
            if(baz = OpenYetAnotherBlah())
                do_something(foo, bar, baz);
                return true;
            {   // oh fuck...
                return false;
            CloseHandle(foo); // don't forget!
            return false;

/* ... */

if(!init_stuff(foo_device, bar_options))
    if(!init_stuff(default_device, failsafe_options))

versus this:

void init_stuff( /* param1, param2 */ )
    scoped_handle foo = CreateWhatever();
    scoped_handle bar = OpenBlah();
    scoped_handle baz = OpenYetAnotherBlah();
    do_something(foo, bar, baz);

/* ... */

    try { init_stuff(foo_device, bar_options); }
        init_stuff(default_device, failsafe_options);

Let's say this runs once at startup... the overhead of possibly throwing a not-too-exceptional exception will be exactly zero. Nobody will notice.



SEH is cool since it doesn't just catch C++ exceptions, but also stuff like segfaults and such. Imagine this imaginary plugin execution code(idea stolen from here):

plugin_func= GetProcAddress(LoadLibrary(....), ....);

   log("Woah, the plugin %s just crashed. I'll disable it.", name);
   // continue as if nothing had happened

You, or a third party developer, or even the end user can supply plugins to your program. Binary code that will be loaded and executed. The plugin might crash, but it won't crash the process, and it won't go undetected (sure, being sufficiently malicious it is of course still possible to crash the process, but you get the idea).


#5242191 Interpretating compessed Data

Posted by samoth on 23 July 2015 - 09:52 AM

10 cannot be divided by 3, so given 3 textures, you can already see that the textures must necessarily share some state, or some really mean bit whacking must take place. Without knowing more details or experimenting for a long time, it's hard to guess which one it is, though.


For example, it could be that there is the requirement that all three textures are the same size. That would mean storing 2 floats instead of 6 for size. Same is possible for scale, too (or scale could simply be uniform).


Packing half-precision floats into normal floats and integers is possible and has been done. GLM has functions for that kind of thing, and if I remember correctly, Cg even had functions (and hardware support on Kepler) for that. OpenGL's ARB_shading_language_packing does that kind of thing, too.


Also, as long as you do not need to interpolate this "float", you could in principle type-pun any collection of arbitrarily-sized integers as a float, for example 6 bits each for the POT size of a texture, and 10 bits each for a scale. After all, to the hardware, it's just a pattern of 32 bits (to some extent).


If textures are required to be power-of-two sized (quite possibly?), there are at most 16 or so possible sizes, thus you could easily pack the texture size into one float and still have room to encode rotation. Even if NPOT textures are allowed, assuming they're at most 2048x4096, they will fit into a float's mantissa no problem, precise to the pixel (with some hefty bit whacking one could fit 16kx16k textures in there too, but that's nasty).


Similarly, scale needs not use the full range of a float, it could very be two half-precision floats. Or, something else, two 16-bit integers type-punned as float, for example.

#5241910 Computer science degree

Posted by samoth on 22 July 2015 - 06:56 AM

While the idea is generally correct, your examples are somewhat unlucky. Also, you should note that computer science and programming do not necessarily have a lot in common.


One should note that Mattrick was appointed as CEO because he had been an executive at Microsoft before, and at EA before that. He became executive at EA not because of a computer science degree, but because EA acquired a company that Mattrick had founded. Being hired for a bigger, better executive position at a competitor is a typical thing in an executive career. Integrating the management stock during an acquisition is standard. So, apart from being fucking cool and founding a nationwide, successful company at the age of 17, Mattrick was lucky, too.


Similarly, Larry Page is not Google's CEO because of a university degree. He founded the company. Being a company founder means being the guy who took all risk and found out it didn't work as well as he had expected 99% of the time, and being the one cool guy who runs a company like Google (usually a bit smaller) in the remaining 1%. It takes a lot of investment (time and money), courage, and of course luck.


Now, Marissa Mayer... she is not just someone with a degree, but someone who ranked in the top ten (maybe top 3) within her field, which just happened to be the field that the then-small Google was urgently interested in. So, yeah, she got a high executive job right away, but not for no reason.


You should not expect to gain a M.S. and be hired as the vice president of IBM a year later. This is not going to happen. Doing some Java programming won't help either. CEOs don't do Java programming, but on the other hand there exist a couple of million of people who do Java programming better (and cheaper) than you.


However, it is realistic to enter a corporation at manager level and haul in a high-5 or low-6 digit annual salary. It's realistic to expect being contacted by headhunters and being offered a better position with more perks (assuming you're not a failure). It's realistic to haul in a mid-6 digit annual salary within a couple of years (if you deliver, and if you play the game right). It's possible to become managing director or such, but this doesn't just fall from the sky only because you have a degree.

#5241906 GLFW or GLEW? Which OpenGL library should I use

Posted by samoth on 22 July 2015 - 06:22 AM

See also this recent, similar question.


In summary, GLFW is what its name says ("GL Frame Work"), a framework. That is, it enforces a kind of structure on your program. Rather than deciding what to do when, you call some initialization functions and tell the framework more or less what you expect, and then the framework calls you back at the appropriate times (for example when the user presses a key or moves the mouse, resizes the window). All you need to do is write handlers for that, the logic behind it is already written. In addition, GLFW comes with a set of useful utility functions. You still write GL code to do the drawing, though.


GLEW on the other hand handles the loading of extensions ("GL Extension Wrangler"). What does that mean? Unlike another well-known graphics API from Microsoft, OpenGL does not come as a set of distinct, entirely different, incompatible versions with different libraries which on the other hand have exactly defined functionality and specs. Instead, OpenGL is a somewhat blurry "everything at the same time, and none" and built in an extendable and heavily extended manner, which is not at all obvious or intuitive to a beginner.

In addition to the base functionality, you can use extensions, if they are supported (there are well over 300 extensions, and the average graphics card driver supports well over a hundred). Additionally, all versions after 1.2 technically work as-if extensions. That is, you cannot just link with opengl32.dll and expect that everything will magically work for OpenGL 3.0 or OpenGL 4.4.


Instead, after creating a context (GLFW will do that for you!) you need to query your context for the supported version and for supported extensions that you may wish to use. Then you must set up a lot of function pointers and initialize them. This is a lot of nasty and error-prone work even for someone reasonably experienced, lest a beginner.


GLEW does all that.


So basically, with GLEW, you call one function to init everything, and then you can very comfortably check what you have available, and use it right away... without having to deal with that nasty stuff.


To answer the question "Which one should I use?" -- in any case you want to use GLEW (or an alternative, but GLEW works fine), but you most likely want to use both GLEW and GLFW since it makes your life easier.

#5241196 Md5 Password Hasher would you use this.

Posted by samoth on 18 July 2015 - 06:13 AM

Having hard time finding bcrypt this is it. How do I know Thats correct.

From the author's name (Niels Provos) in the comments, the file being in the BSD sources, as well as the explanation of how it works. This looks genuine.


It's not important that you use this particular scheme, you could as well use any of the others which are similar. What really matters is that you do not use any single iteration of a hash function, but a high number of iterations. Verifying a password must be slow.


Based on how much security margin you need and on how many server resources you are able (willing) to dedicate to this, anywhere from 5,000 to 100,000 iterations will do. It is a trade-off between how many logins per second your system can handle and between how much time you have to react when your database is compromised. Since you can't do millions of logins per second anyway (neither do you have that many users, nor will your database deliver that fast), it is usually entirely acceptable if you are able to handle a load of, say 100 per second. For a "normal sized" (that is, not the size of Facebook) service, this means that login is still "instantaneous" as perceived by the user.


See also the Wiki pages on bcrypt, scrypt, and pkbdf2 for further choices and info on the subject.


You might even implement this by hand. Usually, that is a "No, no, no!" thing, especially when one doesn't have a lot of experience with writing security related software. Insofar, think twice before diving into that. However, in this particular case, it is tempting because it allows for a low-overhead adaptive solution, and it is probably "allowable" since there is not so much one can do wrong. After all, it's just applying a for loop on a tested, established algorithm.


Technology gets cheaper and faster, and this is something you will inevitably have to deal with from time to time. As hardware gets cheaper and faster, the attacker's life becomes easier.


The nice thing about a "homebrew" build here is that all you need to do is store the number of iterations with each user name (since you need to somehow know that number) in your database. Now, whenever a user logs in, you do the hashing work to verify the password. You do that anyway, it's how the authentification works.


Since you have already done the work of hashing a thousand or so times, you can as well do yet one more hash (or another 3 or 5 if you want). That gives you a different hashed password with more iterations, but at basically zero cost. Store that new hashed password the database together with the new count (and a timestamp to give it an upper cap, like once per day or such, so a malicious user can't exploit this by logging in 10,000 times per day). Now your users' passwords will be rehashed regularly "for free", and the difficulty will slowly but steadily increase.


Alternatively, you can of course have a cron job run over the database once per month or so and rehash all passwords (that will also touch the ones who are never logging in), but then you need to explicitly do the number crunching, so it's not free.

#5241116 Md5 Password Hasher would you use this.

Posted by samoth on 17 July 2015 - 04:27 PM

MD5 is actually not much worse than any other hash for this particular application. The problem with MD5 is that its collision resistence has been shown as being non-existent, which makes it unsuitable for any such thing as signatures (since it takes under 1 second using present-day desktop hardware to break any on MD5-based signature).


However, this is widely irrelevant for its use for storing hashed passwords. The best preimage attack that exists is of theoretical nature and only reduces the complexity by 5 bits. That is still entirely unfeasible. The short length of the MD5 function's output is another concern since obviously having to store a mere 128 bits makes building a rainbow table half as expensive as having to store e.g. 256 bits. Alas, this is also widely irrelevant.


What's relevant, and this is true for every hash function (SHA2 and SHA3 inclusive) is that you can test tens, if not hundreds of millions of passwords per second, and the vast majority of user passwords is in some way dictionary-based or of equally low entropy. Even without a rainbow table (which a salt that only differs by a single bit for every user will successfully thwart), it is a matter of a few minutes to figure out the worst 25-30% of your users' passwords, and a matter of 3-4 days to figure out 80-90% of them all.


Therefore, it is necessary to artificially slow down the hashing process, for example by re-hashing a few thousand times and/or using memory intensive hash algorithms, which make GPU or FPGA implementations much harder. Well-established algorithms exist for that very purpose (e.g. beecrypt or pbkdf2).


That way, it takes weeks to break one password, which gives you enough time to detect an intrusion and alert your users to change passwords. You're playing time.

#5240456 Help me to clear up my confusion about OpenGL

Posted by samoth on 15 July 2015 - 04:37 AM

  • GLUT: Creates a window and context, and invokes callbacks from an event loop. About 20 years old, unmaintained. Somewhat "funny" half-free-proprietary license (no fee for distribution).
  • FreeGLUT: Same as GLUT, but a complete rewrite that is actively maintained. Not 100% compatible/identical (very similar, but some things are different). X/MIT license.
  • GLU: Holds some utility functions as well as software NURBS/tesselation code. Useless to almost everybody nowadays.
  • GLFW: Framework like GLUT or FreeGLUT, but more modern. No compatibility to GLUT whatsoever. Also has extra stuff like joystick support (and I believe threading/sound).


You did not list GLEW (not to be confused with GLFW). Used to load functions beyond OpenGL 1.2, needed for practically everything.




What are the libraries I need to achive goals 1 + 2 (retained mode + loading and using shaders)

GLEW, unless you want to do the function loading by hand (no, you don't want to do that). That's what you need. GLFW or FreeGLUT or GLFW is something you might want to use for the sake of simplicity.


What about Vulkan? Is it worth learning OpenGL right now?

It is worth learning OpenGL now, unless you already know that you will delay your project for another 2 years.


When is Vulkan coming out? Will it differ much from OpenGL?

To date, these are questions nobody can answer. So far, a lot of nice presentations and a lot of marketing talk is publicly available, but no concrete specification, no release date for a specification, or a timeline for implementation by major IHVs.


It appears as if Vulkan will be based on Mantle, with some (minor?) modifications. The sales pitch is that everything is great and everything is much better and blah, but nothing specific is publicly known at this time, nor whether any details that have been published will change.


The specification is anticipated later this year (2nd week of august is likely), but you cannot know for sure until it has happened. The spec can be finalized tomorrow or in 3 years. Or never.

#5239028 Job Manager Lock-Free

Posted by samoth on 08 July 2015 - 12:00 PM

Calling some API is not knowing exactly what happens, that is the opposite.

Well, no, calling an API means making a contract. So, you are in some way right that you don't know exactly what happens. But you do know exactly what the contract is, and I am not aware of any operating system that doesn't fulfill its contracts.


Of course, you have to exactly know your contracts. For example, you cannot use NtReleaseKeyedEvent in the same way as you use sys_futex(FUTEX_WAIT,...).




Well, because sys_futex(FUTEX_WAIT) checks the value prior to blocking, so no wakeups can be missed in case the condition changes concurrently whereas NtWaitForKeyedEvent does not check the value. So you might think it would be possible to miss a wakeup event and being locked out forever. In order to prevent that from happening, NtReleaseKeyedEvent blocks until another thread waits on the same key (or, if you specified a timeout, until it times out).


But, if you respect these little implementation-specific details (and with a bit of discipline you automatically do -- you don't call a wake function when you know that there are no waiters, that's a useless syscall, you just don't do that), I wouldn't know how any weird surprises could happen. The point is, you need some notion of "block me, and let me wake up later" in order to avoid burning CPU forever. This is not achieveable without a syscall of sorts.


Blocking isn't necessarily evil, by the way, it can very well be a performance gain. Imagine two or three threads contending over a spinlock on a single-core machine (the example works for any N+1 threads on any N-core machine). What happens when the first thread grabs the lock and is scheduled out? The other two will start spinning and hope for the value to change. Which, of course, can never possibly happen because the first thread isn't running! Now, if they just decide to give up and block after spinning a dozen times, the first thread will be scheduled again and will run, and thus the system will make progress.


The whole thing about blocking (or yielding) is to make the situation less bad when you're actually already doing things wrong. If you do things right (that is, if your lock is not contended), acquiring the lock is a simple atomic test-and-set operation, and releasing it is writing out a zero value (some compilers, e.g. GCC, and some CPUs have dedicated release intrinsics and instructions for that).


Once you've tried to test-and-set some memory location for some time (same is true for CAS) and it didn't work, what is the best thing you can do? Keep on trying? Or try some time later? Since you have not been successful the last hundred or so times you tried, it seems likely that a lot of other threads are trying the exact same right now. Which is not good, it's not right. But it's what is happening, and you trying again contributes to making the problem worse.

So... yielding might not be the worst plan!


Do you have a guarantee that you will be re-scheduled within some milliseconds? No, of course not. But it's still the best thing you can do in the situation.

#5239022 Simulating the sun

Posted by samoth on 08 July 2015 - 11:36 AM

Do you need a physically (or astronomically) accurate simulation? For most games, it's perfectly sufficient if the sun rises [in Álvaro's coordinate system] at (1,0,0) and sets at (-1,0,0).


The advantage is not only that you have fewer trig operations to do, but also many things like e.g. coarse terrain self-shadowing can be done much easier and more efficiently (also on a CPU). Or, if you want to determine whether a unit is in sunlight for game mechanics / AI / physics (maybe it's a vampire, or maybe you can enter stealth mode when in shadow, enemy units might see you easier when in sunlight), you just sequentially go over the hight field in increasing-x direction. No transformation, no interpolation, no resampling. Just, simple, easy, cache-friendly iteration.

#5238966 Job Manager Lock-Free

Posted by samoth on 08 July 2015 - 06:02 AM

Well, you don't really know how the OS will implement things. So say you make some library that runs on a couple OSes and many versions of it. What is your 'lock'?

Typically, a lock looks somewhat similar to this:

bool try_lock() { return !flag.test_and_set(std::memory_order_acquire); }

void lock()
int count1 = 0; int count2 = 0;

    while(count1++ < SOME_NUMBER1)
        while(count2++ < SOME_NUMBER2) { if(try_lock()) return; _mm_pause(); }

    #if defined(__linux__)
        result = futex_wait(...);
    #elif defined(__WIN32__)
        result = NtWaitForKeyedEvent(...);
        result = pthread_mutex_wait(...);

    if(result == SUCCESS) return;

(This is of course only the simplest possible way, not recursive and no owner, doesn't care about fairness and PI -- much more complicated implementations exist.)


You know quite well what will happen, and when. In particular, you know that this:



like your OS running out of locks and going crazy in spinlock

is something that cannot possibly happen. Why? Well, because you don't allocate kernel objects (such as "locks") at the time you're trying to lock them.

This is a resource that you allocate at, or soon after, program start.


Yes, it is possible that this fails, anything can -- in principle -- fail. It is possible for the operating system to be unable to create a thread or event/semaphore/mutex/whatever kernel object for whatever reason (out of memory, out of handles, ...). In this case your entire system is seriously fucked up and your program failed to initialize properly and cannot run. However, it will not mysteriously fail while you're trying to acquire the lock later.