ThreadSafetyScenarioQuestions

C# Question Bank

C# Threads (Thread Safety / Thread Security) | 10 Scenario Questions (5 Moderate + 5 Complex) — Questions Only

Instruction: Students should implement ONLY the methods marked with // ✅ TODO.
Focus areas: race conditions, atomic updates, deadlock prevention, thread-local security context, safe event dispatch, cancellation, concurrency limits, and thread-safe collections.
Each question includes complex sample input (spaces, quotes, unicode α/β, emoji ✅, special chars). Replace it with your own as required.
Do not add answers in this page.
Moderate: 5 Complex: 5 Coverage: lock, Interlocked, queue producer/consumer, ThreadLocal, deadlock prevention, ReaderWriterLockSlim, SemaphoreSlim, CancellationToken, ConcurrentDictionary, safe event invocation
1

Thread-Safe Hit Counter — lock

ThreadslockRace ConditionModerate

Scenario: Your website counts page hits from multiple threads. Implement a thread-safe increment and read. What to implement: - HitCounter.Increment() - HitCounter.GetValue() Rules: - Must be safe when 20 threads increment 50,000 times each - Use lock (monitor) correctly ✅ Implement ONLY the TODO methods.

✅ Input intentionally includes spaces, quotes, unicode α/β, emoji ✅, and special chars to test parsing + thread-safe processing.
Threads + Thread Safety scenario (students implement ONLY TODO methods) Ctrl+C
using System;                                          // Console
using System.Collections.Generic;                         // List
using System.Threading;                                  // Thread

namespace ItTechGenie.M1.Threads.Q1
{
    public class HitCounter
    {
        private readonly object _gate = new object();      // lock object
        private int _count = 0;                            // shared state

        // ✅ TODO: Student must implement only this method
        public void Increment()
        {
            // TODO: use lock to increment _count safely
            throw new NotImplementedException();
        }

        // ✅ TODO: Student must implement only this method
        public int GetValue()
        {
            // TODO: return _count safely
            throw new NotImplementedException();
        }
    }

    internal class Program
    {
        static void Main()
        {
            var counter = new HitCounter();                // shared counter

            int threads = 20;                              // number of threads
            int incPerThread = 50000;                      // increments per thread

            var list = new List<Thread>();                 // store threads

            for (int i = 0; i < threads; i++)              // start workers
            {
                var t = new Thread(() =>                   // create thread
                {
                    for (int j = 0; j < incPerThread; j++) // repeat increments
                        counter.Increment();               // shared update
                });

                list.Add(t);                               // track thread
                t.Start();                                 // run
            }

            foreach (var t in list) t.Join();              // wait all

            Console.WriteLine("Expected: " + (threads * incPerThread));
            Console.WriteLine("Actual  : " + counter.GetValue());
        }
    }
}
2

Atomic Stock Update — Interlocked

ThreadsInterlockedAtomicModerate

Scenario: An inventory service decrements stock concurrently during flash sale. Use atomic operations to prevent negative stock. What to implement: - Stock.TryPurchase(int qty) -> bool Rules: - If stock is insufficient, return false (no change) - Must be thread-safe with Interlocked.CompareExchange ✅ Implement ONLY the TODO method.

✅ Input intentionally includes spaces, quotes, unicode α/β, emoji ✅, and special chars to test parsing + thread-safe processing.
Threads + Thread Safety scenario (students implement ONLY TODO methods) Ctrl+C
using System;                                          // Console
using System.Threading;                                  // Interlocked

namespace ItTechGenie.M1.Threads.Q2
{
    public class Stock
    {
        private int _available;                            // shared stock

        public Stock(int initial) => _available = initial; // constructor

        public int Available => _available;                // read current (non-atomic ok for display)

        // ✅ TODO: Student must implement only this method
        public bool TryPurchase(int qty)
        {
            // TODO:
            // - validate qty > 0
            // - use CompareExchange loop:
            //   read current, compute next, ensure >=0, CAS update
            throw new NotImplementedException();
        }
    }

    internal class Program
    {
        static void Main()
        {
            var stock = new Stock(1000);                   // initial stock

            int success = 0;                               // count success
            int fail = 0;                                  // count fail

            // create multiple purchase threads
            Thread t1 = new Thread(() => { if (stock.TryPurchase(3)) Interlocked.Increment(ref success); else Interlocked.Increment(ref fail); });
            Thread t2 = new Thread(() => { if (stock.TryPurchase(999)) Interlocked.Increment(ref success); else Interlocked.Increment(ref fail); });
            Thread t3 = new Thread(() => { if (stock.TryPurchase(2)) Interlocked.Increment(ref success); else Interlocked.Increment(ref fail); });

            t1.Start(); t2.Start(); t3.Start();            // run
            t1.Join(); t2.Join(); t3.Join();               // wait

            Console.WriteLine($"Success={success}, Fail={fail}, Remaining={stock.Available}");
        }
    }
}
3

Secure Log Buffer — Producer/Consumer with Queue + lock

ThreadsQueuelockProducer/ConsumerModerate

Scenario: Multiple threads generate security logs. One writer thread flushes them to console/file. Implement a thread-safe in-memory queue. What to implement: - LogBuffer.Enqueue(string msg) - LogBuffer.TryDequeue(out string msg) -> bool Rules: - Must be safe under concurrency - Use a single lock around Queue operations ✅ Implement ONLY the TODO methods.

✅ Input intentionally includes spaces, quotes, unicode α/β, emoji ✅, and special chars to test parsing + thread-safe processing.
Threads + Thread Safety scenario (students implement ONLY TODO methods) Ctrl+C
using System;                                          // Console
using System.Collections.Generic;                         // Queue
using System.Threading;                                  // Thread

namespace ItTechGenie.M1.Threads.Q3
{
    public class LogBuffer
    {
        private readonly object _gate = new object();      // lock object
        private readonly Queue<string> _q = new Queue<string>(); // shared queue

        // ✅ TODO: Student must implement only this method
        public void Enqueue(string msg)
        {
            // TODO: lock and enqueue non-empty msg
            throw new NotImplementedException();
        }

        // ✅ TODO: Student must implement only this method
        public bool TryDequeue(out string msg)
        {
            // TODO: lock; if empty return false; else dequeue and return true
            throw new NotImplementedException();
        }
    }

    internal class Program
    {
        static void Main()
        {
            var buffer = new LogBuffer();                  // shared buffer

            // producers
            Thread p1 = new Thread(() => buffer.Enqueue("[WARN] user='Sana ✅' action='LOGIN' ip='10.0.0.5'"));
            Thread p2 = new Thread(() => buffer.Enqueue("[INFO] user='Ravi#1' action='VIEW' url='/c# threads?x=αβ'"));
            Thread p3 = new Thread(() => buffer.Enqueue("[ERROR] user='"Arjun"' action='FAIL' reason='bad pwd!@#'"));

            p1.Start(); p2.Start(); p3.Start();
            p1.Join(); p2.Join(); p3.Join();

            // consumer
            while (buffer.TryDequeue(out var msg))          // read until empty
                Console.WriteLine(msg);                     // output
        }
    }
}
4

Thread-Local User Context — ThreadLocal<T>

ThreadsThreadLocalSecurity ContextModerate

Scenario: A security pipeline runs on multiple threads. Each thread must keep its own current user. Implement a thread-local context using ThreadLocal<T>. What to implement: - SecurityContext.SetUser(string user) - SecurityContext.GetUser() Rules: - Each thread should see its own user only - Use ThreadLocal<string?> ✅ Implement ONLY the TODO methods.

✅ Input intentionally includes spaces, quotes, unicode α/β, emoji ✅, and special chars to test parsing + thread-safe processing.
Threads + Thread Safety scenario (students implement ONLY TODO methods) Ctrl+C
using System;                                          // Console
using System.Threading;                                  // ThreadLocal, Thread

namespace ItTechGenie.M1.Threads.Q4
{
    public static class SecurityContext
    {
        private static ThreadLocal<string?> _current = new ThreadLocal<string?>(); // per-thread storage

        // ✅ TODO: Student must implement only this method
        public static void SetUser(string user)
        {
            // TODO: store user in thread-local
            throw new NotImplementedException();
        }

        // ✅ TODO: Student must implement only this method
        public static string? GetUser()
        {
            // TODO: return thread-local value
            throw new NotImplementedException();
        }
    }

    internal class Program
    {
        static void Main()
        {
            Thread t1 = new Thread(() => { SecurityContext.SetUser("Sana ✅");  Console.WriteLine("T1 user=" + SecurityContext.GetUser()); });
            Thread t2 = new Thread(() => { SecurityContext.SetUser("Ravi#1");  Console.WriteLine("T2 user=" + SecurityContext.GetUser()); });
            Thread t3 = new Thread(() => { SecurityContext.SetUser("Arjun α/β"); Console.WriteLine("T3 user=" + SecurityContext.GetUser()); });

            t1.Start(); t2.Start(); t3.Start();
            t1.Join(); t2.Join(); t3.Join();

            Console.WriteLine("Main user=" + SecurityContext.GetUser());        // should be null by default
        }
    }
}
5

Prevent Deadlock — Consistent Lock Ordering

ThreadsDeadlock Preventionlock orderingModerate

Scenario: Two resources (Account A and Account B) need transfer. Multiple threads may transfer between accounts causing deadlocks if locks are inconsistent. What to implement: - TransferService.SafeTransfer(Account from, Account to, decimal amount) Rules: - Must avoid deadlock by locking accounts in a consistent order (e.g., by Id) - Use lock with ordering strategy ✅ Implement ONLY the TODO method.

✅ Input intentionally includes spaces, quotes, unicode α/β, emoji ✅, and special chars to test parsing + thread-safe processing.
Threads + Thread Safety scenario (students implement ONLY TODO methods) Ctrl+C
using System;                                          // Console
using System.Threading;                                  // Thread

namespace ItTechGenie.M1.Threads.Q5
{
    public class Account
    {
        public int Id { get; }                             // unique id
        public decimal Balance { get; private set; }        // balance

        public Account(int id, decimal bal)                // constructor
        {
            Id = id;                                       // assign
            Balance = bal;                                 // assign
        }

        public void Debit(decimal amt) => Balance -= amt;   // debit
        public void Credit(decimal amt) => Balance += amt;  // credit
    }

    public static class TransferService
    {
        // ✅ TODO: Student must implement only this method
        public static void SafeTransfer(Account from, Account to, decimal amount)
        {
            // TODO:
            // - validate amount > 0
            // - lock accounts in consistent order (by Id) to avoid deadlock
            // - then debit/credit
            throw new NotImplementedException();
        }
    }

    internal class Program
    {
        static void Main()
        {
            var a = new Account(101, 1000m);
            var b = new Account(202, 1000m);

            Thread t1 = new Thread(() => TransferService.SafeTransfer(a, b, 100m));
            Thread t2 = new Thread(() => TransferService.SafeTransfer(b, a, 50m));

            t1.Start(); t2.Start();
            t1.Join(); t2.Join();

            Console.WriteLine($"A={a.Balance}, B={b.Balance}");
        }
    }
}
6

Thread-Safe Cache — ReaderWriterLockSlim

ThreadsReaderWriterLockSlimCacheComplex

Scenario: A pricing cache is read very often, and written rarely. Use ReaderWriterLockSlim to maximize reads without blocking. What to implement: - PriceCache.Get(string key) -> decimal? - PriceCache.Set(string key, decimal value) Rules: - Keys may contain spaces/special chars/unicode - Use EnterReadLock/EnterWriteLock properly with try/finally - Store in Dictionary<string, decimal> ✅ Implement ONLY the TODO methods.

✅ Input intentionally includes spaces, quotes, unicode α/β, emoji ✅, and special chars to test parsing + thread-safe processing.
Threads + Thread Safety scenario (students implement ONLY TODO methods) Ctrl+C
using System;                                          // Console
using System.Collections.Generic;                         // Dictionary
using System.Threading;                                  // ReaderWriterLockSlim

namespace ItTechGenie.M1.Threads.Q6
{
    public class PriceCache
    {
        private readonly Dictionary<string, decimal> _map = new Dictionary<string, decimal>(); // store
        private readonly ReaderWriterLockSlim _rw = new ReaderWriterLockSlim(); // lock

        // ✅ TODO: Student must implement only this method
        public decimal? Get(string key)
        {
            // TODO: read lock; try get value; return null if missing
            throw new NotImplementedException();
        }

        // ✅ TODO: Student must implement only this method
        public void Set(string key, decimal value)
        {
            // TODO: write lock; set value safely
            throw new NotImplementedException();
        }
    }

    internal class Program
    {
        static void Main()
        {
            var cache = new PriceCache();
            cache.Set("SKU-α12", 1299.50m);

            Console.WriteLine(cache.Get("SKU-α12"));
            Console.WriteLine(cache.Get("Missing ✅"));
        }
    }
}
7

Rate-Limited Worker — SemaphoreSlim

ThreadsSemaphoreSlimRate limitingComplex

Scenario: A background job calls an external service for 100 user records. To protect credentials and avoid throttling, allow only N concurrent calls. What to implement: - RateLimitedRunner.RunAllAsync(List<string> userIds, int maxConcurrent) Rules: - Use SemaphoreSlim to limit concurrency - Use Task.Run to simulate work (Thread.Sleep allowed in demo) - Collect results thread-safely (ConcurrentBag or lock) ✅ Implement ONLY the TODO method.

✅ Input intentionally includes spaces, quotes, unicode α/β, emoji ✅, and special chars to test parsing + thread-safe processing.
Threads + Thread Safety scenario (students implement ONLY TODO methods) Ctrl+C
using System;                                          // Console
using System.Collections.Generic;                         // List
using System.Threading;                                  // SemaphoreSlim
using System.Threading.Tasks;                             // Task
using System.Collections.Concurrent;                      // ConcurrentBag

namespace ItTechGenie.M1.Threads.Q7
{
    public static class RateLimitedRunner
    {
        // ✅ TODO: Student must implement only this method
        public static async Task<List<string>> RunAllAsync(List<string> userIds, int maxConcurrent)
        {
            // TODO:
            // - validate inputs
            // - create SemaphoreSlim(maxConcurrent)
            // - for each userId: wait semaphore, run task, release semaphore in finally
            // - collect results thread-safely and return list
            throw new NotImplementedException();
        }
    }

    internal class Program
    {
        static async Task Main()
        {
            var ids = new List<string> { "u-α12", "u-β77", "user "Sana ✅"", "user Ravi#1", "user Arjun α/β" };
            var results = await RateLimitedRunner.RunAllAsync(ids, 2);

            Console.WriteLine("Results:");
            results.ForEach(Console.WriteLine);
        }
    }
}
8

Secure Cancellation — Cooperative Stop with CancellationToken

ThreadsCancellationTokenCooperative cancelComplex

Scenario: A malware scan runs in background and must stop safely on cancel request. Implement a worker that checks CancellationToken frequently. What to implement: - Scanner.Run(CancellationToken token, IEnumerable<string> files) -> int scannedCount Rules: - Stop quickly if token cancelled - Use token.ThrowIfCancellationRequested OR token.IsCancellationRequested checks - No partial shared-state corruption ✅ Implement ONLY the TODO method.

✅ Input intentionally includes spaces, quotes, unicode α/β, emoji ✅, and special chars to test parsing + thread-safe processing.
Threads + Thread Safety scenario (students implement ONLY TODO methods) Ctrl+C
using System;                                          // Console
using System.Collections.Generic;                         // IEnumerable
using System.Threading;                                  // CancellationTokenSource

namespace ItTechGenie.M1.Threads.Q8
{
    public static class Scanner
    {
        // ✅ TODO: Student must implement only this method
        public static int Run(CancellationToken token, IEnumerable<string> files)
        {
            // TODO:
            // - iterate files
            // - check token in loop
            // - simulate scan (Thread.Sleep)
            // - return scanned count
            throw new NotImplementedException();
        }
    }

    internal class Program
    {
        static void Main()
        {
            var files = new List<string>
            {
                @".\uploads\invoice ""Feb ✅"".pdf",
                @".\uploads\img_α12.png",
                @".\uploads\temp!!@#.bin",
                @".\uploads\report β77.txt"
            };

            var cts = new CancellationTokenSource();        // cancel source

            // cancel quickly in another thread
            new Thread(() => { Thread.Sleep(120); cts.Cancel(); }).Start();

            try
            {
                int scanned = Scanner.Run(cts.Token, files);
                Console.WriteLine("Scanned=" + scanned);
            }
            catch (OperationCanceledException)
            {
                Console.WriteLine("Scan cancelled ✅");
            }
        }
    }
}
9

Thread-Safe Token Store — ConcurrentDictionary + GetOrAdd

ThreadsConcurrentDictionaryGetOrAddSecurity tokensComplex

Scenario: Multiple threads request auth tokens for the same user. Token generation is expensive; only generate once per user and reuse. What to implement: - TokenStore.GetToken(string userId) -> string Rules: - Use ConcurrentDictionary<string,string> - Use GetOrAdd so generation runs once per key - Token value must include random-ish suffix and preserve special chars in userId ✅ Implement ONLY the TODO method.

✅ Input intentionally includes spaces, quotes, unicode α/β, emoji ✅, and special chars to test parsing + thread-safe processing.
Threads + Thread Safety scenario (students implement ONLY TODO methods) Ctrl+C
using System;                                          // Console
using System.Collections.Concurrent;                      // ConcurrentDictionary
using System.Threading;                                  // Thread

namespace ItTechGenie.M1.Threads.Q9
{
    public class TokenStore
    {
        private readonly ConcurrentDictionary<string, string> _tokens = new ConcurrentDictionary<string, string>(); // store

        // ✅ TODO: Student must implement only this method
        public string GetToken(string userId)
        {
            // TODO:
            // - validate userId
            // - use _tokens.GetOrAdd(userId, key => GenerateToken(key))
            // - implement token generation inside lambda using Guid
            throw new NotImplementedException();
        }
    }

    internal class Program
    {
        static void Main()
        {
            var store = new TokenStore();

            string[] ids = { "user "Sana ✅"", "user Ravi#1", "user Arjun α/β", "user "Sana ✅"" };

            var threads = new Thread[ids.Length];
            for (int i = 0; i < ids.Length; i++)
            {
                int idx = i;
                threads[i] = new Thread(() =>
                {
                    var token = store.GetToken(ids[idx]);
                    Console.WriteLine(ids[idx] + " => " + token);
                });

                threads[i].Start();
            }

            foreach (var t in threads) t.Join();
        }
    }
}
10

Thread-Safe Event Dispatch — Copy Delegate Before Invoke

ThreadsEventsThread-safe invocationComplex

Scenario: A security monitor raises an alert event from multiple threads. You must invoke the event safely to avoid NullReference + race conditions. What to implement: - SecurityMonitor.Raise(string message) Rules: - Event: public event Action<string>? Alert; - Use local copy of delegate before invoking - Do not hold locks while calling subscribers (avoid re-entrancy deadlocks) ✅ Implement ONLY the TODO method.

✅ Input intentionally includes spaces, quotes, unicode α/β, emoji ✅, and special chars to test parsing + thread-safe processing.
Threads + Thread Safety scenario (students implement ONLY TODO methods) Ctrl+C
using System;                                          // Action
using System.Threading;                                  // Thread

namespace ItTechGenie.M1.Threads.Q10
{
    public class SecurityMonitor
    {
        public event Action<string>? Alert;                // subscribers

        // ✅ TODO: Student must implement only this method
        public void Raise(string message)
        {
            // TODO:
            // - validate message
            // - copy Alert to local variable
            // - invoke local copy if not null
            throw new NotImplementedException();
        }
    }

    internal class Program
    {
        static void Main()
        {
            var m = new SecurityMonitor();

            // subscriber 1
            m.Alert += msg => Console.WriteLine("[EMAIL] " + msg);

            // subscriber 2
            m.Alert += msg => Console.WriteLine("[SMS ] " + msg);

            // raise from multiple threads
            Thread t1 = new Thread(() => m.Raise("ALERT: suspicious login user='Sana ✅' ip='10.0.0.5'"));
            Thread t2 = new Thread(() => m.Raise("ALERT: brute force user='Ravi#1' count=5!!@#"));
            Thread t3 = new Thread(() => m.Raise("ALERT: token reuse user='Arjun α/β'"));

            t1.Start(); t2.Start(); t3.Start();
            t1.Join(); t2.Join(); t3.Join();
        }
    }
}