Se le chiamate a SP1 seguite da SP2 sono atomiche, devono essere combinate in T-SQL. Oppure perdere la transazione c#. Stai prolungando inutilmente la transazione con viaggi di andata e ritorno.
Inoltre, perché avere UPDLOCK su SP1UPDLOCK ma non per SP1? Non riesco a vedere perché. Se il problema sono i suggerimenti per il blocco, non utilizzarli. Se qualcosa è serializzabile (perché?), fallo di nuovo in una singola chiamata atomica
Nota che l'impostazione predefinita è comunque READ COMMITTED
Infine, intendi "semaforo" non bloccato? Utilizzo di sp_getapplock controllerà il flusso attraverso il codice senza utilizzare blocchi sui dati