There are at least 2 business processes involved here.

- Process one:

Show available seats.


- Process two:

Book a selected seat.

Since these processes don't follow one another immoderately, and since 2 people may select the same seat the concurrency issue arises.

If your database design assigns the correct uniqueness constraint so that the combination of:
-TheaterID
-SeatID
-EventID

are unique, then the database will prevent duplicates. 

The following scenario is also possible but will be taken care of by the above suggested implementation:

Assuming a grid view of available for a given theater and a given event can be displayed:

1. User1 displays available seats (and gets seats 1 and 2)
2. User2 displays available seats (and gets seats 1 and 2) 
3. User1 talks a bit with the customer on the phone
4. User2 goes and books seat 2 for his customer
5. User1 tries to book seat 2 for his customer (because it shows as available on his screen)
6. The unique index prevents step 5 from commuting the data.

So all what you need to do may be nothing more correct database design and proper choice on constraints.

Other more complex approaches are possible if you want, using transaction queues. In this case, requests are written first to a queue that fires every n seconds but that is hardly necessary.

The really interesting part is what should the list grid for user 1 show?