• Advertisement

King Mir

  • Content count

  • Joined

  • Last visited

Community Reputation

2498 Excellent

About King Mir

  • Rank
    Advanced Member

Personal Information

  • Interests
  1. initialize std::thread

    So if I understand you, what you're saying is that this generates a fence on Visual Studio: volitile LONG var = 0; var += 10l; However, you think this won't even though the first argument is volatile: volatile LONG var = 0; InterlockedAddNoFence(var, 10l); If so, I think you're right.
  2. initialize std::thread

    Several things: InterlockedAdd is a compiler intrinsic, for which the compiler is aware of the semantics. As such, the compiler should know not to reorder instructions around it. If you were to implement InterlockedAdd yourself, you are correct that it is possible to get it wrong, if you don't communicate the fencing semantics of an atomic instruction to the compiler. Note, these fencing semantics do not imply an actual fence instruction on every architecture. I would recommend using C/C++ 11 atomics over compiler intrinsics such as these to avoid learning all the nuances of each compilers intrinsics, including InterlockedAdd. As for the processor executing your instruction out of order, I disagree that fences are needed in x86. The proof is here, http://www.cl.cam.ac.uk/~pes20/cpp/popl085ap-sewell.pdf, though I don't claim to have read and understood all of it myself. I believe it shows that a locked instruction is sufficient on all atomic stores to guarantee sequential consistency. You are right that locked instructions do not prevent a value from changing after you have read it, but this does not prevent you from being able to reason about your program having sequential consistency. Yes, you still need correct algorithms that don't assume that a shared value will necessarily still be of the value last read from it, unless otherwise guaranteed in code.
  3. initialize std::thread

    That's backwards. The entire point of using atomic operations is so the compiler adds those fences. I can't figure out from the linked documentation if InterlockAdd has sequentially consistent semantics, or merely acquire/release semantics, and therefore if it would require a locked instruction, or not on x86. A locked instruction would be sufficient for sequentially consistent semantics on x86, so you don't need a fence.
  4. initialize std::thread

    Yes, it does look like InterlockedAdd would get you the rest of the way, based on a quick look. But why wouldn't you just use std::atomic<T>? Especially if using std::thread. Also, a complication here is that Microsoft's compiler by default implements volatile as atomic, adding those fences that the language does not require it to.
  5. initialize std::thread

    Volatile is both too much and not enough for multi-threaded synchronization. Volatile prevents the compiler from putting a value in a register, and it makes the compiler treat reads and writes as IO for ordering purposes. But what it does not to is provide memory fences to prevent the processor from reordering synchronization instructions. Therefore, using atomics (with sequentially consistent memory order) will actually generate different assembly then using volatile. On weaker processor architectures, the difference is more pronounced, but even x64 now has Non-Temporal SSE instructions, which need more fences. And technically, any program that has a shared data not synchronized by threading primitives (which volatile isn't), is undefined.
  6. If you want multi threading, you need synchronization. Otherwise you'll get spurious nondeterministic errors. Anything shared between threads needs to be synchronized. And for an engine you probably do want multi threading support so that you can make use of multiple cores.
  7. Signing is not about buying trust, it's about buying traceability. You're preventing someone from adding malware to your executable and distributing it in your name.
  8. Not protocol, library. With many languages there is a standard networking library, with others you have some choices. For those, you will need to pick a library. You can probably google "<language> networking library" for you language.
  9. Question 1: Language doesn't matter very much on the server side. Java is a common choice. But you can choose whatever you're familiar with. Even javascript is an option, which has the advantage that your client and server are written in the same language. Along with choosing a language you will at the same time need to choose a network library. Question 2: You can't really have one thread per game, because player actions are driven by events like a player sending a message to the server. So the way this works is you have a listener that triggers whenever anybody makes a move, or when a timer triggers. Now there's a choice to be made. Do you allow clients to persist connections to the server or do you make a "REST" api. With persistent connections, there is less verification after the connection is made; you don't need to verify who is sending the data every time; you are able to associate some data with the connection. The server is able to send messages to the client without waiting for the client to ask for it. If the connection breaks you would need to handle that either as "user has left the game" or by allowing users to reconnect. With a REST api, you would have a single connection per client action. The server is unable to reach out to the client, but the client could ask the server every so many seconds if it has something new. Each request would need to be authenticated to figure out which client or user it is coming from. The server has no visibility to if the client has disconnected. With this approach it is easier to have multiple servers, because the server does not have implicit state in the connection, so any server can respond to any request. Question 3: I don't know. As you think about this, also consider supporting retina displays, which have high resolution for the same screen size, therefore allowing more detail, but larger icons and fonts.
  10. That's true, but that is a different question: when to do a calculation client side or server side. And it's orthogonal. You can store the data on each user's machine, then send it to the server when a user connects. Or you can use other means to attempt to ensure the authenticity of the client application. In a 3d multi-player game it may be prohibitively slow or server intensive to make all calculations server side, so relying on client authenticity may be necessary, at least some of the time. For example, for things like obscured objects, generally you would want to rely on a graphics card to hide things outside the player view, instead of computing server side what the user can see, even though a hacked client could be made to see through walls (unless countermeasures are taken). That being said, using a database with the server has another advantage: it allows you to have multiple servers that talk to the same database, allowing more horizontal scaling. So even if some data is stored on the client, it probably still makes sense for the server to have a data store anyway.
  11. It's not quite true that data on the users computer can't be trusted. You can trust data that has been digitally signed by the server. For example, you could send a file to the server, have it verify it, and return a signature. When loading the game this signature can be verified. Verifying the signature can be done with a public key, and does necessarily not require communication with the server. Or, if the data you wish to save is duplicated between the client and server, you can simply have the server send the digital signature to be saved. When the client attempts to save, it will verify that the data it generates matches the signature and save both. It is important that both the client and server compute all save data in a deterministically identical way in this case.
  12. So boost has a "call_traits" library that solves this for setters and other function parameters. Essentially, what it does is special case for built in types, pointer types, etc, and assume a large object for all user provided class types. Like boost, you can provide a helper template for the best way to pass T to setters and other functions. Or you can use enable_if, other sfinae mechanisms, or template specialization to achieve the same thing. With getters, you kind of need to choose either const T & or T and be consistent because it will effect how the function can be used. I don't see any point in providing a set function if get returns a T &. If you do want a function that just returns a T &, consider making it operator *, and following the interface of std::optional.
  13. I haven't worked enough with cocos2d-x, but I expect that there's no "master" font unless you explicitly tell it to do something like that. This is easy enough to test though, so you'd probably get your answers quicker by testing than waiting for replies here; see what happens when you load two fonts in different order and see which one takes precedence for printing both shared and unshared characters. You might also be able to leverage native fonts on the machine instead of importing your own, especially for the limited case of the facebook login screen.
  14. So the problem with "not obsessing over making things exact" is that that could encourage micromanagement, because a micromanaging player can manage better than the ai in that case. I would prefer a system that just works for player and ai alike. That said, I'm not sure my current design squares up with that goal entirely; a player will be able to optimize by adjusting export priorities. With that in mind, I'm inclined to follow your original advice and use rational numbers.
  15. So if you're interested, here's the algorithm I'm using in some detail: For each city, A, (in an order that is complex to go into -- this isn't really a for loop but a recursive graph traversal) needs = demand of this city + all cities it exports to available = surplus of all importers added together For each city, B, that imports to A city_available = (production of B) - (all the previously calculated exports of B) if needs < available import ( (city_available / available) * needs ) resources else import (city_available) resources (Then calculate how much each city that city A exports to gets -- I haven't done this part yet) The outer order requires that cities have a priority of who they export to. For example a city would choose to export first to London, then everything that's left goes to Canterbury. But London is not going to prefer where its goods come from; demand is equal on all importers, and all of them end up with surplus if they can't pass it on their excess to Canterbury. Now I wish I could get rid of the need to have export priorities, but I'm pretty sure that would make the whole calculation a way too complex differential equation. As you can see, this takes an equal amount from each importer, even if it's a fractional amount; no remainder.
  • Advertisement