2022년 3월 3일 목요일

[c# Spinlock]

 using System;

using System.Threading;
using System.Threading.Tasks;



/// <summary>
/// deadLock
///
//
/// </summary>

namespace ServerCore
{
    /// <summary>
    /// 존버매타
    ///
    ///
    ///
    /// </summary>
    class SpinLock
    {
        /// volatile 가시성 보장!
        /// 가시성이 뭔지 다시 보기!
        volatile int _locked = 0;

        public void Acquire()
        {
            ///이렇게 그냥 사용하면
            ///Interlocked.Exchange(ref _locked, 1);
            ///_locked = 1; ///이거랑 다를바 없음


            while (true)
            {
                int original = Interlocked.Exchange(ref _locked, 1);///return original value 하기때문에 리턴값을보고 우리가 바꿧는지 아니면 다른데서 사용해서 바뀐건지 확인 할 수 있음
                if (original == 0)
                {
                    ///아무도 없을때 !
                    break;

                }


                {
                    ///싱글스레드 였을때의 표현
                    ///하지만 멀티에서는 먹히지않는다!
                    ///두번 만에 진행되기때문에!(원자성문제)
                    int ori = _locked;
                    _locked = 1;
                    if (ori == 0)
                        break;
                }

                {
                    if (_locked == 0)
                        _locked = 1;
                }
            }







            ///이 부분이 한번에 처리 안되서 문제
            ///두개 동시에 와일을 탓을때가 문제다!
            /*while (_locked)
            {
                /// 잠김이 풀리기를 기다린다.
            }


            _locked = true;
            ///내꺼!*/
            ///do something...
        }

        public void Release()
        {
            _locked = 0;
        }
    }

   
    class Program
    {
        static int _num = 0;
        static SpinLock _lock = new SpinLock();

        static void Thread_1()
        {
            for (int i = 0; i < 10000; i++)
            {
                _lock.Acquire();
                _num++;
                _lock.Release();
            }
        }

        static void Thread_2()
        {
            for (int i = 0; i < 10000; i++)
            {
                _lock.Acquire();
                _num--;
                _lock.Release();
            }
        }


        static void Main(string[] args)
        {
            Task t1 = new Task(Thread_1);
            Task t2 = new Task(Thread_2);
            t1.Start();
            t2.Start();

            Task.WaitAll(t1, t2);

            Console.WriteLine(_num);
        }
    }
}



using System;
using System.Threading;
using System.Threading.Tasks;



/// <summary>
/// deadLock
///
//
/// </summary>

namespace ServerCore
{
    /// <summary>
    /// 존버매타
    ///
    ///
    ///
    /// </summary>
    class SpinLock
    {
        /// volatile 가시성 보장!
        /// 가시성이 뭔지 다시 보기!
        volatile int _locked = 0;

        public void Acquire()
        {
            ///이렇게 그냥 사용하면
            ///Interlocked.Exchange(ref _locked, 1);
            ///_locked = 1; ///이거랑 다를바 없음


            while (true)
            {
                /*int original = Interlocked.Exchange(ref _locked, 1);///return original value 하기때문에 리턴값을보고 우리가 바꿧는지 아니면 다른데서 사용해서 바뀐건지 확인 할 수 있음
                if (original == 0)///아무도 없을때 !
                    break;*/

                /// CAS Compare-And-Swap
                /// if(_locked==0)
                /// _locked=1; 이런느낌

                int expected = 0;///예상한값(lock걸리기 전)
                int desired = 1;///예상한값이 맞다면 넣어야할값(lock걸기)


                ///뺑뺑이 돌면서 획득할때까지 돌리기
                if(Interlocked.CompareExchange(ref _locked, desired, expected) == expected)
                    break;
               


             
            }







            ///이 부분이 한번에 처리 안되서 문제
            ///두개 동시에 와일을 탓을때가 문제다!
            /*while (_locked)
            {
                /// 잠김이 풀리기를 기다린다.
            }


            _locked = true;
            ///내꺼!*/
            ///do something...
        }

        public void Release()
        {
            ///이미 문을 열어놨기 때문에 이 변수 write하는거에 대해서 문제 될 것이 없다!!
            _locked = 0;
        }
    }

   
    class Program
    {
        static int _num = 0;
        static SpinLock _lock = new SpinLock();

        static void Thread_1()
        {
            for (int i = 0; i < 10000; i++)
            {
                _lock.Acquire();
                _num++;
                _lock.Release();
            }
        }

        static void Thread_2()
        {
            for (int i = 0; i < 10000; i++)
            {
                _lock.Acquire();
                _num--;
                _lock.Release();
            }
        }


        static void Main(string[] args)
        {
            Task t1 = new Task(Thread_1);
            Task t2 = new Task(Thread_2);
            t1.Start();
            t2.Start();

            Task.WaitAll(t1, t2);

            Console.WriteLine(_num);
        }
    }
}

댓글 없음:

댓글 쓰기

git rejected error(feat. cherry-pick)

 문제 아무 생각 없이 pull을 받지않고 로컬에서 작업! 커밋, 푸시 진행을 해버렷다. push에선 remote와 다르니 당연히 pull을 진행해라고 하지만 로컬에서 작업한 내용을 백업하지 않고 진행하기에는 부담스럽다(로컬작업 유실 가능성) 해결하려...