Tuesday, 15 March 2016

15th March

Bitmasks - use when you want to save some space when using variables
Can use a field of bits to pass many arguments to a function without the need for a struct
Can also save parameter space, imagine a function which has to take 20 different booleans, you'd have to pass many true/false declarations
Instead just take a single int and then call the function with the options enabled
Can return something like status&aliveFlag - when using &, both things must be true

Vector creates a container of bits - it is not standard (sometimes causes issues)
for (auto& v : bools) is an easy way to iterate through a vector, checking if true
std::bitset<sizeOfBitset> bitsetName (hex value for which bit you want enabled)
can use .set, .flip, .reset with a bitset

Custom allocators
Deleting an already deleted object breaks the program, so making a custom deleter can be a good way to circumvent that problem
Customised new and delete functions, if done properly, will almost always be as fast as or faster than the default new and delete functions
Can lead to a significant speed up!!!!!

Compiler automatically adds padding to the size of variables (bit size) to make sure that each new variable starts on an even number in its memory location

To summarise, bitmasks are good to save space and make code more legible. Custom made functions and such to overwrite stock compiler ones are usually not worth the effort especially for amateur programmers. Automatic padding can be helpful but when it isn't, it can be manipulated

8th March

Exceptions
Exceptions allow you to react to strange behaviour
Throw - throws an exception when a problem shows up
Catch - catches an exception with a handler where you want
Try - helps you identify the code that is wrong and tries something
Ellipsis catch (...) is default handler, like a switch statement default
Try blocks can be nested (try in try in try...) and throwing can pass a try back up
We can use try/catch to stop division by zero so that our program doesn't break (only if we try to catch though)

Look for exception, throw error, handle it.
c++ has many exceptions like bad_alloc built in
But you need to include <exception> to catch them, and you have to use try
We can make our own exceptions by overriding (eg use struct)
When to use - empty disk drive, etc: external issues that we cannot control, so we can send an error message
There is a cost, sometimes dramatic, for using exceptions so use them sparingly
Also don't use for code that has to run as fast as possible
There is a no cost method, a table that maps out where in your code an exception might be required so that it only runs when it is needed, and thus only slows the program using memory when needed (which is unlikely as it is usually a failsafe)
Exception-safe code is where even if an exception is made, it won't affect the program at all
Basic guarantee leaves code valid, strong guarantee guarantees the code will be the same

Assertions
Allows you to abort program if something is true
Simply, assertion is to make sure of something, if that thing is false then stop immediately
Program will terminate with no cleanup, may create a dump
If a bug is unable to be found you can assert if you know what is wrong, break into when the bug is after time
Final release versions of program will usually have asserts cut out via the compiler to allow for a smaller executable
Both happen during runtime, exceptions are for outside of your control issues, assertions are for inside.

Sunday, 6 March 2016

29th Feb

A crash dump works similar to a normal debugging does. It has break points, but once it is paused, it cannot be resumed - it is simply a dump, a frozen instance of the program's current state (rather, the state it was in when the dump happened).
Depending on the type of the dump, symbol files may be required. There are modules in Visual Studio that can load symbol files, so symbol files are readily compatible with Visual Studio.
Symbols are like placeholders (or mappings) of variable names and function names, linked to their memory address. Symbols are used during the linking part of compilation, so when a symbol problem occurs, the program should still compile and build... This might end up being harder to spot and fix for someone unfamiliar with symbols.
Symbols are placed in a table. This table is found within an Object file (.obj) within the current project.

PDB files (program database files) are linked to and only compatible with the version of Visual Studio that they were built against. They are a collection of symbol information which is stored to save time later.
PDB files are created whenever you build a solution, created by the compiler. These files allow for incremental updates.

These are both very useful debugging tools if used properly.

Monday, 29 February 2016

23 Feb

Task Groups

Can create a queue dedicated for one type of queue eg logic, thread runs throughs this
With queue/task group system we can make sure certain threads depend on other events and maintain their order
Eg when rendering is done, send event to animation (do not run before)

Can still be improved - system to create thread-specific queue
Could use CPU affinities (bind thread to a particular core)
Allow some tasks to have higher priority (useful for important tasks so they run first)
Can also batch up similar tasks (group them together)

Mutexes
Deals with shared data - shared data can cause issues
Mutex is a program object that allows multiple threads to access the same resource safely
Mutex can protect shared data by locking it
Offers exclusive, non-recursive ownership semantics (not repetitious)
Useful when one thread may read and another may write
This is known as being 'under concurrent read and writes'
Thread can wait for a mutex to unlock data or skip it if it is not vital
A mutex is a semaphore - object designed for concurrent usage
std::mutex mutexName; to create a mutex
mutexName.lock(); to lock the mutex and disallow other threads reading/writing
std::lock_guard<std::mutex>guard(mutexName); this creates a mutex that automatically unlocks after the thread has run (and is out of scope)
std::defer.lock to make sure the mutex doesn't lock automatically, an amount of time can be placed in

Atomics
Since mutexes are best used for low contention threads, we need something for high contention too
Atomics can be used
An operation type, it appears in all intents and purposes to occur instantaneously as a single operation
Must ensure your ordering to be able to use properly
Use fencing (border, threads) to achieve this
Fence tells compiler: you must use the order this is written in
std::atomic<int>intName; to create one.
Store (write) and load (read)
Use std::thread threadName (constructorName) to pass constructor and run as function pointer
All threads have a unique ID - can see this ID using std::this_thread::get_id();
this_thread:: always writes for current thread and stores in future

Could make threaded task instead(faster?) and store result of execution to std::future
std::async will always run immediately (no deferring)
Prefer using task - for the simple use of future to return value
Inside task an exception can be used to cancel (and close) that particular thread instead of the whole program, if something goes wrong
Can run out of threads, but not tasks
Threads can also cause slowdown if too many threads are called; tasks don't necessarily all run so any excess tasks won't cause any slowdown.

In summary: use threaded tasks

Monday, 8 February 2016

Feb 2

Transport Protocols

TCP = transmission control protocol
UDP = user datagram protocol

TCP guarantees all information will be sent, but is slow
UDP does not guarantee all information's delivery but is fast
While TCP requires a connection, UDP does not have to connect directly
TCP will retransmit information if it is reported lost by the receiver

Sockets
These provide the interface for data transmission
TCP can cut this data into chunks if necessary and send them that way; recombines it when it is received and the correct order is guaranteed
UDP can send data simultaneously. Sometimes known as multi-casting, this allows it to send data to multiple PCs as it doesn't need a connection
There are 2 different nodes unique to either the server or client. For the server there is a listening node and for the client there is a connecting lode
Server needs multiple sockets to support each client, and at least another spare to listen for additional clients
SF::TCPLISTENER is a class to listen for upcoming connections
Accept is a blocking call; blocking calls stop the thread for as long as the network's timer lasts for (up to 2 seconds), then resume

UDP do not need a specific connection but they do need an assigned node listener
Sending data is the same regardless of which protocol is used
All you have to do is define the name and size of the data, and for using UDP the destination must also be defined
It is generally a bad idea to send arrays of bytes
socket.received must include a parameter for how much data was sent
The wait function can be used with an if else statement
using (selector.wait(sf::seconds(10)) with 10 seconds as the example
A selector does not store data (assuming it only selects it)
Exchanging is more difficult than simply sending data. Data must be compatible both ways
Commonly known as packets during exchange
SFML provides constant types that will always work as they will be the same regardless of platform. One example is:
sf::Int32; which is a 32 bit piece of data

sf::Packet works like a normal stream operator, using the >> symbols like cin, cout etc do
packet << x << s << d; sends a packet
packet >> x >> s >> d; receives a packet

It is possible to encrypt or compress sf packets
Add a simple function to encrypt/compress before the data is sent and one for decrypting and decompressing after the packet is received
The client receives a different type of packet so this needs to be factored in as well.

A dumb terminal is a client that sends simple information to the server and does not act upon it. An example is a first person shooter client telling the server that player 1 has clicked, and where.
Server processes this information and sends it back not only to the original client, but every other client connected to the server
This, however, will always cause a delay - latency of the clients determines how much of a delay
Some clients can use rubber banding and other predictions based on what the user has done but this would no longer be seen as a dumb terminal

The peer to peer networking method has no central server so each individual client controls what happens in the game; that information is then sent to every peer
This is exploitable as a server would usually have checks for cheating, without the server it can be easy for users to change the game code to cheat
Peer to peer isn't as commonly used because of this cheating

Interpolation is prediction for what will happen in a multiplayer game. The client guesses what the player's input will achieve and does it before sending to the server; when the server sends the data back the player might teleport or move around strangely as a result of a wrong prediction. Otherwise, interpolation cuts down on latency
Extrapolation can also be used. It is still guessing but it is this time based on current movement and velocity - more of a calculation based on previous input and the assumption that the player will keep moving in that direction
No matter what, multiplayer experience will always be limited by ping, the latency and time it takes for data to be sent and return