Even with serializers, it's not easy to do a good job of writing programs that deal successfully with concurrency. In fact, all of the operating systems in widespread use today have bugs in this area; Unix systems, for example, are expected to crash every month or two because of concurrency bugs.
To make the discussion concrete, let's think about an airline reservation system, which serves thousands of simultaneous users around the world. Here are the things that can go wrong:
Deadlock. Suppose that someone wants to travel to a city for which there is no direct ﬂight. We must make sure that we can reserve a seat on ﬂight A and a seat on connecting ﬂight B on the same day, before we commit to either reservation. This probably means that we need to use two serializers at the same time, one for each ﬂight. Suppose we say something like
(serializer-A (serializer-B (lambda () ...))))
Meanwhile someone else says
(serializer-B (serializer-A (lambda () ...))))
The timing could work out so that we get serializer A, the other person gets serializer B, and then we are each stuck waiting for the other one (forever!).
Depending on the particular program you're writing, the definition of correct behavior might differ. Typically, a concurrent program is said to display correct behavior if it produces the same result as if the processes had run sequentially in some order. There are two important aspects to this requirement.
First, it does not require the processes to actually run sequentially, but only to produce results that are the same as if they had run sequentially.
Second, there may be more than one possible "correct" result produced by a concurrent program, because we require only that the result be the same as for some sequential order.