There are multiple schools of thought regarding the use of version control systems.
My preference is to try to keep each upcoming feature worked in a separate feature branch (pretty much no matter how small). The person(s) assigned for this feature then only have their own changes to work on; no interference comes from the other developers.
Bug fixes (aside from truly trivial ones) also go first in as separate branches, just to keep the trunk line stable and clean. Latest trunk revision always corresponds to the last delivered version (release) of the product.
When a new release is being prepared, if there is only a single change coming, and that change itself is based on the previously delivered version, then the tests can be run against the branch version, and at time of new release, changes from the branch are simply integrated into the trunk version. Version control systems such as cvs and svn have decent support for this kinds of merge operations (I haven't been working with git myself, but understand that branches and merges are handled well there as well).
If there are several distinct changes to be integrated, I prefer to create a separate "integration" branch, to which I first collect one by one all the changes to be integrated. Again, the version control systems do flag when there are conflicting edits (i.e. two different changes in one place of a single code file). What they understandably cannot tell is if there are functional conflicts caused by several distinct changes. So at least some oversight, and prefrably also testing, will be needed after each integration.
Then, when all the individual changes have been integrated to the integration branch, it can be thoroughly tested, and again merged to the trunk when it is ready for release. If there are further corrections to be made, they can be developed further in the original feature branches, and then the corrections integrated agani to the integration branch.
This way lends itself very well to fast bug correction response, as the trunk always contains the last release. It also lends itself nicely to speculative development, as the distinct feature branches only affect the trunk line when integrated. Also, features can be worked over several release cycles, as releases do not affect the ongoing development in feature branches. This way the "bus factor" (what happens if one of the developers is run over by a bus) is also reduced; incomplete and even incompilable code can be checked in in the feature branches -- and all work done is available for other developers if for any reason someone is missing from work. Also, workstation disasters do not cause a significant worry, as would be if the workstation could easily hold one weeks worth of development work not checked in, not backed up.
Whether to update the long-lived feature branches always to latest releases as new releaases are made is a question of policy, and also may depend on what went in in the last release. Another question of policy is the ownership of the integration branch; whether there's some single person responsible for collecting all the feature branch changes and making the needed smal changes to make them fit with the other changes, or whether each feature developer/team will be responsible for getting the changes from that specific feature branch to the integration branch. I favor the separate "release builder" (who of course typically is one of the feature developers).
At least in my reality it seems that 3-4 devs can pretty well work in a single branch, if they otherwise communicate with each other (shared office space is the preferred way). They do organise their work themselves, and can avoid stepping on each others' toes. Also, the separate feature branches seem to rather seldom touch the same files with each other, so most of the merge cycles are rather painless (and the painful ones can be predicted by the change descriptions). On the other hand, even a single developer multi-taskng over several distinct but simultaneous change tasks will end up in trouble, if the changes are not isolated in branches.
So, in a summary: do not lock files, but instead have a good version control system, utilize branches bravely, and keep your eyes open when merging changes from branches.