It does. The critical section problem still exists: for all practical purposes, you must treat it as if there are two CPUs. In addition, there is a "yield" instruction that should be used by spin-locks, which will give control to the other CPU in a hyper-threaded processor.
If the hyperthreaded CPU acts identically to a real 2 CPU machine, I'll spring for one of those ASAP.
No, it doesn't. The two CPUs in a hyperthreaded processor share some functional units. I'm not sure which ones, but the floating point unit is a likely candidate. So, if both CPUs try to do a floating point operation at the same time, one must wait for the other to finish.
Intel claims that running two instances of the same application on a hyper-threaded CPU yields a 15-30% increase in throughput. SPECint_rate2000 measures about 10% increase in throughput.
I figured the critical section issues would be more exacting. I'm accustomed to doing that already. UNIX device drivers need to be protected from interrupts with spl8()/splx(old) guards. In QNX, I put a "sleep(0)" statement in selected loop threads to yield the CPU back to another thread. The monitor facilities in Java and C# make locking a critical section easier. I suspect the impacts on each of these types of critical sections will differ a bit on a hyperthreaded processor.