Consider a simple Registry class accessed by multiple threads:
public class Registry
{
    protected readonly Dictionary<int, string> _items = new Dictionary<int, string>();
    protected readonly object _lock = new object();
    public void Register(int id, string val)
    {
        lock(_lock)
        {
           _items.Add(id, val);
        }
    }
    public IEnumerable<int> Ids
    {
        get
        {
            lock (_lock)
            {
                return _items.Keys;
            }
        }
    }
}
and typical usage:
var ids1 = _registry.Ids;//execution deferred until line below
var ids2 = ids1.Select(p => p).ToArray();
This class is not thread safe as it's possible to receive System.InvalidOperationException 
Collection was modified; enumeration operation may not execute.
when ids2 is assigned if another thread calls Register as the execution of _items.Keys is not performed under the lock!
This can be rectified by modifying Ids to return an IList:
public IList<int> Ids
    {
        get
        {
            lock (_lock)
            {
                return _items.Keys.ToList();
            }
        }
    }
but then you lose a lot of the 'goodness' of deferred execution, for example
var ids = _registry.Ids.First();  //much slower!
So,
1) In this particular case are there any thread-safe options that involve IEnumerable
2) What are some best practices when working with IEnumerable and locks  ?