I was not sure about posting this as an answer, since it is basically some more considerations on the three existing answers (for reference, they are Michel Keijzers's one - using digitalRead -, Craig's one - read the PIND variable at once -, Filip Franik's one - use interrupts), but it became quite long and so a single comment could not fit all of this.
What you and the other answerers wrote is in theory correct. Checking the button of player 1 before player 2 gives an advantage to player one. What you lack is... How much advantage?
Mechanical actions (such as the pressing of a button) have a time duration that is around 50ms*.
Since I assume your application is a reaction time tester, human reaction times are around 250ms.
Moreover mechanical buttons have "bounces". Typical debounce times are in the range 20-100ms. You can avoid this by just checking the first edge.
A player gets an advantage if he is awarded as winner even if the button was pressed at the same time.
_* I tried to find a source for this, but I was not able to get some data. I tried with an online stopwatch and pressing the two spacebars (notebook and USB keyboard) roughly at the same time, obtaining results around 75ms. This is not a real value, so if someone has some measured values or estimations feel free to comment
Now, let's assume you properly coded your program so that you check for ties and avoid delays, since these will greatly affect the following measurements.
digitalRead case you are executing this series of actions:
- Read status of pin 1 - 3.6us
- Read status of pin 2 - 3.6us
- Check the statuses and decide who won - some tens of instructions (about 1us)
- Loop - a couple instructions (0.5us)
The 60 instructions comes from this thread (3.6us = 57.8 instructions @16MHz); as for the others it's a rough measurement. Let's assume that the function actually samples the pin at the very end of the function.
Now, since you are checking for ties, if both buttons get pressed during phases 3, 4 or 1 you will get a tie (since both buttons will be read as pressed). If both buttons get pressed during phase 2, button 2 will be marked as pressed and button 1 not, thus giving advantage to that player. The time when this happens is about 3.6us long. So you are giving a 3.6us advantage to button 2 player.
In the PIND case you are reading the buttons exactly at the same time. The advantage is thus 0.
In the interrupt case when both EXT0 and EXT1 interrupts are triggered at the same time EXT0 gets executed, since it is before in the ISR. Consequently the player pressing the button on EXT0 has one interrupt checking cycle of advantage. I admit I do not know how often the inputs are checked for the EXT interrupt, but I assume it performs a check every clock cycle (consequently the advantage is 62.5ns).
Now, let's sum up the advantage
- digitalRead: 3.6us
- PIND: 0
- interrupt: 62.5ns
The solution is pretty obvious to me, and it is... Don't care! Even in the worst case scenario you are four order of magnitude faster than your phenomenon. You are giving one player a 4us advantage in a 250ms game (0.0016% of advantage). I'm pretty sure that the mechanical differences between the two buttons (maybe one is a bit stiffer, or has a slightly higher size, or has a slightly lower contact) affect the reading much more than this.
In the end, with this kind of setup you will reasonably be able to have an accuracy that is at most some tens of milliseconds. With other measurement setups (maybe optically based) you can go as low as 1ms. Adding 4us of advantage to one player will not influence the result.
Try to focus on the rest of the program, and for this problem use whichever solution you find more understandable.
NOTE: This is based on the assumption that a proper program is developed, with tie checks and no delays and so on. The program as you wrote in the question is not ok from this point of view (as it is now it will stay in the loop forever; if you change
digitalRead it will become roughly fair - something like 4us of advantage to player one and 3.8us of advantage to player two)