Update single table with mutually exclusive threads
Yes, it's ok to use (READPAST, UPDLOCK) where inUse = 0.


UPDLOCK hint will force SQL Server to use (U) locks instead of (S) locks and (U) locks are incompatible with each other, so the two threads will not be able to fetch the same row.

READPAST hint will force SQL Server to skip the locked rows rather than being blocked.


The batches are not "gone". They are just not always consist of records with consecutive IDs. 


To illustrate this , let's add a FetchTime column to the table and modify the relevant parts of the procedure:

      DECLARE MY_CURSOR CURSOR 
         LOCAL STATIC READ_ONLY FORWARD_ONLY
         FOR 
         SELECT top X Id,GETUTCDATE() as FetchTime 
         FROM Names WITH (READPAST, UPDLOCK)
         where inUse = 0
         order by 1


.
.
.

  OPEN MY_CURSOR
        FETCH NEXT FROM MY_CURSOR INTO @Id,@Fetchtime


.
.
.

 update Names set InUse = 1, Thread = @Thread,FetchTime=@FetchTime where id = @Id


All the rows in a batch will have the same value in the FetchTime column.

Now it is more evident that the batches are not "gone" : 




Yes. In fact, this approach is more efficient than synchronizing access to the table by implementing a critical section or using a mutex because the two threads can read the data in parallel without blocking each other.