초기커밋

This commit is contained in:
2025-05-01 07:20:41 +09:00
commit 98bb2e3c5c
2747 changed files with 646947 additions and 0 deletions

View File

@@ -0,0 +1,123 @@
using System;
using System.Net;
using System.Threading;
using GAURD_KEY = System.String;
namespace ServerCore;
//=============================================================================================
// 병렬 프로그래밍 환경에서 특정 로직이 동시에 실행되지 않도록 보호하는 클래스 이다.
//
// author : kangms
//
//=============================================================================================
public class AtomicGuard : IDisposable
{
private string m_try_guard_key = string.Empty;
private string m_using_guard_key = string.Empty;
private AtomicString? m_guard_key_nullable;
private AtomicBool? m_atomic_bool_nullable;
public AtomicGuard(GAURD_KEY guardKey)
{
m_try_guard_key = guardKey;
}
public AtomicGuard(AtomicString guardKey)
{
m_guard_key_nullable = guardKey;
}
public AtomicGuard(AtomicString guardKey, AtomicBool atomicBool)
{
m_guard_key_nullable = guardKey;
m_atomic_bool_nullable = atomicBool;
}
public bool tryGuard()
{
if (null == m_guard_key_nullable)
{
var err_msg = $"m_guard_key_nullable is null !!! in tryGuard() - guardKey:{m_try_guard_key}";
Log.getLogger().error(err_msg);
return false;
}
if(false == m_guard_key_nullable.compareAndSet(string.Empty, m_try_guard_key))
{
var err_msg = $"Failed to in compareAndSet() !!! in tryGuard() - guardKey:{m_try_guard_key}";
Log.getLogger().info(err_msg);
return false;
}
if (null == m_atomic_bool_nullable)
{
var err_msg = $"m_atomic_bool_nullable is null !!! in tryGuard() - guardKey:{m_try_guard_key}";
Log.getLogger().error(err_msg);
return false;
}
if (false == m_atomic_bool_nullable.set(true))
{
var err_msg = $"Failed to set true !!! in tryGuard() - guardKey:{m_try_guard_key}";
Log.getLogger().info(err_msg);
return false;
}
m_using_guard_key = m_try_guard_key;
return true;
}
public void Dispose()
{
if (null == m_guard_key_nullable)
{
var err_msg = $"m_guard_key_nullable is null !!! in Dispose() - guardKey:{m_try_guard_key}";
Log.getLogger().error(err_msg);
return;
}
var guard_key = m_guard_key_nullable.Value;
if (false == m_guard_key_nullable.compareAndSet(m_using_guard_key, string.Empty))
{
var err_msg = $"Failed to compareAndSet() !!! in Dispose() : usingGuardKey:{m_using_guard_key} - guardKey:{guard_key}";
Log.getLogger().info(err_msg);
return;
}
if (null == m_atomic_bool_nullable)
{
var err_msg = $"m_atomic_bool_nullable is null !!! in Dispose() - guardKey:{guard_key}";
Log.getLogger().error(err_msg);
return;
}
if (false == m_atomic_bool_nullable.set(false))
{
var err_msg = $"Failed to set false in Dispose() !!! - guardKey:{guard_key}";
Log.getLogger().error(err_msg);
return;
}
}
public void bindAtomic(AtomicString guardKey, AtomicBool atomicBool)
{
m_guard_key_nullable = guardKey;
m_atomic_bool_nullable = atomicBool;
}
}

View File

@@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ServerCore;
//=============================================================================================
// 병렬 프로그래밍 환경에서 특정 로직이 동시에 실행되지 않도록 Monitor를 활용하여 보호하는 클래스 이다.
//
// author : kangms
//
//=============================================================================================
public class AutoLock : IDisposable
{
private readonly object m_lock;
public AutoLock(object tolockObject)
{
m_lock = tolockObject;
Monitor.Enter(m_lock);
}
public void Dispose()
{
Monitor.Exit(m_lock);
}
}

View File

@@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ServerCore;
public class Counter
{
private uint m_count = 0;
private readonly uint m_min;
private readonly uint m_max;
public Counter(uint min = uint.MinValue, uint max = uint.MaxValue)
{
m_min = min;
m_max = max;
}
public uint incCount()
{
var value = Volatile.Read(ref m_count);
if(value >= m_max)
{
m_count = m_max;
return m_count;
}
return Interlocked.Increment(ref m_count);
}
public uint decCount()
{
var value = Volatile.Read(ref m_count);
if (value <= m_min)
{
m_count = m_min;
return m_count;
}
return Interlocked.Decrement(ref m_count);
}
public uint getCount()
{
return Volatile.Read(ref m_count);
}
}

View File

@@ -0,0 +1,53 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ServerCore;
public class InstantIdGeneratorWith32Bit
{
private UInt32 m_index = 0;
public InstantIdGeneratorWith32Bit()
{
}
public UInt32 nextId()
{
Interlocked.Increment(ref m_index);
if(m_index == UInt32.MaxValue)
{
throw new OverflowException("UInt32.MaxValue has been reached, at InstantIdGeneratorWith32Bit.nextId() !!!");
}
return m_index;
}
}//InstantIdGeneratorWith32Bit
public class InstantIdGeneratorWith64Bit
{
private UInt64 m_index = 0;
public InstantIdGeneratorWith64Bit()
{
}
public UInt64 nextId()
{
Interlocked.Increment(ref m_index);
if (m_index >= UInt64.MaxValue)
{
throw new OverflowException("UInt64.MaxValue has been reached, at InstantIdGeneratorWith64Bit.nextId() !!!");
}
return m_index;
}
}//InstantIdGeneratorWith64Bit

View File

@@ -0,0 +1,178 @@
namespace ServerCore;
//=============================================================================================
// 병렬 프로그래밍 환경에서 상태값을 동기화할 수 있게 지원하는 제네릭 클래스 이다.
//
// author : kangms
//
//=============================================================================================
public class SyncState<T> where T : notnull
{
private T m_state;
private readonly object m_mutex = new object(); // mutex
public SyncState(T state)
{
m_state = state;
}
public bool isState(T state)
{
lock (m_mutex)
{
return (m_state.Equals(state));
}
}
public T setState(T state)
{
lock (m_mutex)
{
T old_state = m_state;
m_state = state;
return old_state;
}
}
public T getState()
{
return m_state;
}
// 같지 않으면 변경
// exchange..(disconnected, out old_state)
public bool exchangeNotEqual(T to_state, out T old_state)
{
lock (m_mutex)
{
if (false == m_state.Equals(to_state))
{
old_state = m_state;
m_state = to_state;
return true;
}
old_state = m_state;
return false;
}
}
// 같지 않으면 변경, 예외인 경우는 변경안함
// exchange...(disconnected, connecting, out old_state)
public bool exchangeNotEqualExcept(T to_state, T except_state, out T old_state)
{
lock (m_mutex)
{
// except state
if (true == m_state.Equals(except_state))
{
old_state = m_state;
return false;
}
if (false == m_state.Equals(to_state))
{
old_state = m_state;
m_state = to_state;
return true;
}
old_state = m_state;
return false;
}
}
public string? toString()
{
return Enum.GetName(typeof(T), m_state);
}
}
public class AtomicString
{
private string m_value;
public AtomicString(string value = "")
{
m_value = value;
}
public string Value
{
get { return m_value; }
}
public void set(string newValue)
{
Interlocked.Exchange(ref m_value, newValue);
}
public bool compareAndSet(string expectedValue, string newValue)
{
return Interlocked.CompareExchange(ref m_value, newValue, expectedValue) == expectedValue;
}
}
public class AtomicInt32
{
private Int32 m_value;
public AtomicInt32(Int32 value = 0)
{
m_value = value;
}
public int Value
{
get { return m_value; }
}
public void set(int newValue)
{
Interlocked.Exchange(ref m_value, newValue);
}
public int increment()
{
return Interlocked.Increment(ref m_value);
}
public int decrement()
{
return Interlocked.Decrement(ref m_value);
}
public int add(int value)
{
return Interlocked.Add(ref m_value, value);
}
public bool compareAndSet(int expectedValue, int newValue)
{
return Interlocked.CompareExchange(ref m_value, newValue, expectedValue) == expectedValue;
}
}
public class AtomicBool
{
private Int32 m_value = 0;
public AtomicBool(bool value)
{
m_value = value ? 1 : 0;
}
public bool Value
{
get { return m_value == 1; }
}
public bool set(bool value)
{
var comparand = value ? 0 : 1;
var in_value = value ? 1 : 0;
var result = Interlocked.CompareExchange(ref m_value, in_value, comparand);
return comparand == result;
}
}

View File

@@ -0,0 +1,434 @@
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Google.Protobuf.WellKnownTypes;
namespace ServerCore;
//=============================================================================================
// 병렬 프로그래밍 환경에서 특정 객체의 Read & Write 처리를 ReaderWriterLockSlim 활용하여
// 동기화해주는 클래스 이다.
//
// author : kangms
//
//=============================================================================================
public class Synchronizer<TObject>
where TObject : class
{
private readonly ReaderWriterLockSlim m_rw_lock;
private readonly TObject m_value;
public Synchronizer(TObject value)
{
ArgumentNullReferenceCheckHelper.throwIfNull(value, () => $"value is null !!!");
m_value = value;
var dynamic_obj = (value as dynamic);
ArgumentNullException.ThrowIfNull(dynamic_obj, "dynamic_obj is null !!!");
m_rw_lock = dynamic_obj.getRWLock();
}
//=============================================================================================
// 호출자의 읽기를 위한 로직을 동기화 해준다.
// ReaderWriterLockSlim의 EnterReadLock() 호출하여 동기화 해준다.
//=============================================================================================
public TResult callReadFunc<TResult>(Func<TObject, TResult> readFunc)
{
ArgumentNullReferenceCheckHelper.throwIfNull(readFunc, () => $"readFunc is null !!!");
m_rw_lock.EnterReadLock();
try
{
return readFunc(m_value);
}
finally
{
m_rw_lock.ExitReadLock();
}
}
//=============================================================================================
// 호출자의 쓰기를 위한 로직을 동기화 해준다.
// ReaderWriterLockSlim의 EnterWriteLock() 호출하여 동기화 해준다.
//=============================================================================================
public TResult callWriteFunc<TResult>(Func<TObject, TResult> writeFunc)
{
ArgumentNullReferenceCheckHelper.throwIfNull(writeFunc, () => $"writeFunc is null !!!");
m_rw_lock.EnterWriteLock();
try
{
return writeFunc(m_value);
}
finally
{
m_rw_lock.ExitWriteLock();
}
}
public IDisposable tryReadLock()
{
m_rw_lock.EnterReadLock();
return new Unlocker(m_rw_lock, isReadLock: true);
}
public IDisposable tryWriteLock()
{
m_rw_lock.EnterWriteLock();
return new Unlocker(m_rw_lock, isReadLock: false);
}
}
//=============================================================================================
// Synchronizer를 복수개로 처리할 때 사용하는 클래스 이다.
//
// author : kangms
//
//=============================================================================================
public class MultipleSynchronizer<TObject>
where TObject : class
{
private readonly ConcurrentDictionary<string, Synchronizer<TObject>> m_synchronizers = new();
public MultipleSynchronizer(Dictionary<string, TObject> toSyncObjects)
{
foreach (var each in toSyncObjects)
{
var synchronizer = new Synchronizer<TObject>(each.Value);
m_synchronizers[each.Key] = synchronizer;
}
}
//=============================================================================================
// 등록된 객체중에서 locks 파라메터에 의해 선택적으로 Read & Write Lock을 설정해 준다.
//=============================================================================================
public MultiLock tryLockAll(IEnumerable<(string Key, bool IsReadLock)> locks)
{
return new MultiLock(m_synchronizers, locks);
}
//=============================================================================================
// 등록된 모든 객체를 Read Lock 설정을 해준다.
//=============================================================================================
public MultiReadLock tryReadLockAll()
{
return new MultiReadLock(m_synchronizers);
}
//=============================================================================================
// 등록된 모든 객체를 Write Lock 설정을 해준다.
//=============================================================================================
public MultiWriteLock tryWriteLockAll()
{
return new MultiWriteLock(m_synchronizers);
}
public Synchronizer<TObject> this[string index] => m_synchronizers[index];
public class MultiLock : IDisposable
{
private readonly List<IDisposable> m_lock_objects;
public MultiLock(ConcurrentDictionary<string, Synchronizer<TObject>> syncObjects, IEnumerable<(string Key, bool IsReadLock)> locks)
{
m_lock_objects = new List<IDisposable>();
foreach (var (key, isReadLock) in locks)
{
if (true == syncObjects.TryGetValue(key, out var found_object))
{
m_lock_objects.Add(isReadLock ? found_object.tryReadLock() : found_object.tryWriteLock());
}
}
}
public void Dispose()
{
foreach (var lock_obj in m_lock_objects)
{
lock_obj.Dispose();
}
}
}
public class MultiReadLock : IDisposable
{
private readonly List<IDisposable> m_lock_objects;
public MultiReadLock(IEnumerable<KeyValuePair<string, Synchronizer<TObject>>> syncObjects)
{
m_lock_objects = new List<IDisposable>();
foreach (var each in syncObjects)
{
m_lock_objects.Add(each.Value.tryReadLock());
}
}
public void Dispose()
{
foreach (var lock_obj in m_lock_objects)
{
lock_obj.Dispose();
}
}
}
public class MultiWriteLock : IDisposable
{
private readonly List<IDisposable> m_lock_objects;
public MultiWriteLock(IEnumerable<KeyValuePair<string, Synchronizer<TObject>>> syncObjects)
{
m_lock_objects = new List<IDisposable>();
foreach (var each in syncObjects)
{
m_lock_objects.Add(each.Value.tryWriteLock());
}
}
public void Dispose()
{
foreach (var lock_obj in m_lock_objects)
{
lock_obj.Dispose();
}
}
}
}
//=============================================================================================
// 병렬 프로그래밍 환경에서 특정 객체의 Read & Write 처리를 ReaderWriterLockSlim 활용하여
// async 기반으로 동기화해주는 클래스 이다.
//
// author : kangms
//
//=============================================================================================
public class SynchronizerAsync<TObject>
where TObject : class
{
private readonly ReaderWriterLockSlim m_rw_lock;
private readonly TObject m_value;
public SynchronizerAsync(TObject value)
{
m_value = value;
m_rw_lock = (value as dynamic).getRWLock();
}
//=============================================================================================
// 호출자의 읽기를 위한 로직을 async 기반으로 동기화 해준다.
// ReaderWriterLockSlim의 tryReadLockAsync() 호출하여 동기화 해준다.
//=============================================================================================
public async Task<TResult> callReadFuncAsync<TResult>(Func<TObject, Task<TResult>> readFunc)
{
ArgumentNullReferenceCheckHelper.throwIfNull(readFunc, () => $"readFunc is null !!!");
await m_rw_lock.tryReadLockAsync();
try
{
return await readFunc(m_value);
}
finally
{
m_rw_lock.ExitReadLock();
}
}
//=============================================================================================
// 호출자의 쓰기를 위한 로직을 async 기반으로 동기화 해준다.
// ReaderWriterLockSlim의 tryWriteLockAsync() 호출하여 동기화 해준다.
//=============================================================================================
public async Task<TResult> callWriteFuncAsync<TResult>(Func<TObject, Task<TResult>> writeFunc)
{
ArgumentNullReferenceCheckHelper.throwIfNull(writeFunc, () => $"writeFunc is null !!!");
await m_rw_lock.tryWriteLockAsync();
try
{
return await writeFunc(m_value);
}
finally
{
m_rw_lock.ExitWriteLock();
}
}
public async Task<IDisposable> tryReadLockAsync()
{
return await m_rw_lock.tryReadLockAsync();
}
public async Task<IDisposable> tryWriteLockAsync()
{
return await m_rw_lock.tryWriteLockAsync();
}
}
//=============================================================================================
// SynchronizerAsync를 복수개로 처리할 때 사용하는 클래스 이다.
//
// author : kangms
//
//=============================================================================================
public class MultipleSynchronizerAsync<TObject>
where TObject : class
{
private readonly ConcurrentDictionary<string, SynchronizerAsync<TObject>> m_synchronizers = new();
public MultipleSynchronizerAsync(Dictionary<string, TObject> toSyncObjects)
{
foreach (var each in toSyncObjects)
{
var synchronizer = new SynchronizerAsync<TObject>(each.Value);
m_synchronizers[each.Key] = synchronizer;
}
}
//=============================================================================================
// 등록된 객체중에서 locks 파라메터에 의해 선택적으로 Read & Write Lock을 설정해 준다.
//=============================================================================================
public MultiLockAsync tryLockAllAsync(IEnumerable<(string Key, bool IsReadLock)> locks)
{
return new MultiLockAsync(m_synchronizers, locks);
}
//=============================================================================================
// 등록된 모든 객체를 Read Lock 설정을 해준다.
//=============================================================================================
public MultiReadLockAsync tryReadLockAllAsync()
{
return new MultiReadLockAsync(m_synchronizers);
}
//=============================================================================================
// 등록된 모든 객체를 Write Lock 설정을 해준다.
//=============================================================================================
public MultiWriteLockAsync tryWriteLockAllAsync()
{
return new MultiWriteLockAsync(m_synchronizers);
}
public SynchronizerAsync<TObject> this[string index] => m_synchronizers[index];
public class MultiLockAsync : IDisposable
{
private readonly List<IDisposable> m_lock_objects;
public MultiLockAsync(ConcurrentDictionary<string, SynchronizerAsync<TObject>> syncObjects, IEnumerable<(string Key, bool IsReadLock)> locks)
{
m_lock_objects = new List<IDisposable>();
foreach (var (key, isReadLock) in locks)
{
if (true == syncObjects.TryGetValue(key, out var found_object))
{
m_lock_objects.Add(isReadLock ? found_object.tryReadLockAsync() : found_object.tryWriteLockAsync());
}
}
}
public void Dispose()
{
foreach (var lock_obj in m_lock_objects)
{
lock_obj.Dispose();
}
}
}
public class MultiReadLockAsync : IDisposable
{
private readonly List<IDisposable> m_lock_objects;
public MultiReadLockAsync(IEnumerable<KeyValuePair<string, SynchronizerAsync<TObject>>> syncObjects)
{
m_lock_objects = new List<IDisposable>();
foreach (var each in syncObjects)
{
m_lock_objects.Add(each.Value.tryReadLockAsync());
}
}
public void Dispose()
{
foreach (var lock_obj in m_lock_objects)
{
lock_obj.Dispose();
}
}
}
public class MultiWriteLockAsync : IDisposable
{
private readonly List<IDisposable> m_lock_objects;
public MultiWriteLockAsync(IEnumerable<KeyValuePair<string, SynchronizerAsync<TObject>>> syncObjects)
{
m_lock_objects = new List<IDisposable>();
foreach (var each in syncObjects)
{
m_lock_objects.Add(each.Value.tryWriteLockAsync());
}
}
public void Dispose()
{
foreach (var lock_obj in m_lock_objects)
{
lock_obj.Dispose();
}
}
}
}
//=============================================================================================
// Unlocker가 소멸될 때 ReaderWriterLockSlim가 Exit 될 수 있도록 해주는 클래스 이다.
//=============================================================================================
public class Unlocker : IDisposable
{
private readonly ReaderWriterLockSlim m_ref_rw_lock;
private readonly bool m_is_read_lock;
public Unlocker(ReaderWriterLockSlim readWriteLockObject, bool isReadLock)
{
m_ref_rw_lock = readWriteLockObject;
m_is_read_lock = isReadLock;
}
public void Dispose()
{
if (m_is_read_lock)
{
m_ref_rw_lock.ExitReadLock();
}
else
{
m_ref_rw_lock.ExitWriteLock();
}
}
}

View File

@@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Text;
using System.Threading.Tasks;
namespace ServerCore;
public static class SynchronizerHelper
{
public static async Task<IDisposable> tryReadLockAsync(this ReaderWriterLockSlim rwLock)
{
ArgumentNullReferenceCheckHelper.throwIfNull(rwLock, () => $"rwLock is null !!!");
return await Task.Run(() =>
{
rwLock.EnterReadLock();
return (IDisposable) new Unlocker(rwLock, false);
});
}
public static async Task<IDisposable> tryWriteLockAsync(this ReaderWriterLockSlim rwLock)
{
ArgumentNullReferenceCheckHelper.throwIfNull(rwLock, () => $"rwLock is null !!!");
return await Task.Run(() =>
{
rwLock.EnterWriteLock();
return (IDisposable) new Unlocker(rwLock, true);
});
}
}

View File

@@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ServerCore;
//=============================================================================================
// 서버로 부터 수신한 시간을 기준 시간으로 설정시켜
// 서버 시간을 기준으로 동기화되어 관리될 수 있는 기능을 지원하는 클래스 이다.
//
// author : kangms
//
//=============================================================================================
public class TimeSyncHelper
{
private readonly string m_server_type = string.Empty;
private DateTime m_server_time = ConstDateTimeValue.MinTime;
private System.Diagnostics.Stopwatch m_stop_watch = new System.Diagnostics.Stopwatch();
public TimeSyncHelper(string serverType)
{
m_server_type = serverType;
}
public void setupFromTimeServer(DateTime serverTime, TimeSpan ping)
{
m_server_time = serverTime.toUtcTime().AddMilliseconds(ping.TotalMilliseconds / 2);
m_stop_watch = m_stop_watch ?? new System.Diagnostics.Stopwatch();
m_stop_watch.Reset();
m_stop_watch.Start();
}
public DateTime getCurrentByTimeServer()
{
return m_server_time + m_stop_watch.Elapsed;
}
}