Подтвердить что ты не робот

Мне нужно создать статическую переменную, защищенную потоком, в С#.Net

ok, это немного сложнее, чем вопрос.

class A
{
   static int needsToBeThreadSafe = 0;

   public static void M1()
   {
     needsToBeThreadSafe = RandomNumber();
   }

   public static void M2()
   {
     print(needsToBeThreadSafe);
   }
}

теперь я требую, чтобы между вызовами M1() и M2() "needsToBeThreadSafe" остается Thread Safe.

4b9b3361

Ответ 1

То, о чем вы можете попросить, это атрибут [ ThreadStatic]. Если вы хотите, чтобы каждый поток, который использует класс A, имеет собственное значение needsToBeThreadSafe, вам просто нужно украсить это поле с помощью ThreadStatic].

Для получения дополнительной информации см. документацию MSDN для ThreadStaticAttribute.

Ответ 2

Как насчет:

public static void M1()
{
    Interlocked.Exchange( ref needsToBeThreadSafe, RandomNumber() );
}

public static void M2()
{
    print( Interlocked.Read( ref needsToBeThreadSafe ) );
}

Ответ 3

У вас есть два варианта: самым простым с учетом вашего представленного кода является ключевое слово volatile. объявите needsToBeThreadSafe как static volatile int, и это гарантирует, что любой поток, который ссылается на эту переменную, получит "последнюю" копию, а переменная не будет кэшироваться внутри вашего кода.

Если вы хотите в более общем плане обеспечить, чтобы M1() и M2() выполнялись "атомарно" (или, по крайней мере, исключительно друг из друга), тогда вы хотите использовать lock. Самый чистый синтаксис имеет "блокирующий блок", например:

private static object locker = new Object();

//..

public static void M1()
{
    lock(locker)
    {
        //..method body here
    }
}

public static void M2()
{
    lock(locker)
    {
        //..method body here
    }
}

Что касается того, какой подход взять, что до вас и должен определяться кодом. Если все, что вам нужно, это обеспечить, чтобы назначение участника распространялось на все потоки и не кэшировалось, тогда ключевое слово volatile проще и сделает работу просто прекрасной. Если это возможно, вы можете пойти с lock.

Ответ 4

class A
{
   static int needsToBeThreadSafe = 0;
   static object statObjLocker = new object();

   public static void M1()
   {
       lock(statObjLocker)
       {
          needsToBeThreadSafe = RandomNumber();
       }
   }

   public static void M2()
   {
       lock(statObjLocker)
       {
          print(needsToBeThreadSafe);
       }
   }
}

Ответ 5

Звучит так, как будто вам нужен Volatile.

static volatile int needsToBeThreadSafe = 0;

Ответ 6

Вы также можете использовать ReaderWriterLockSlim, который более эффективен для нескольких чтений и меньше записей:

static int needsToBeThreadSafe = 0;
static System.Threading.ReaderWriterLockSlim rwl = new System.Threading.ReaderWriterLockSlim();

public static void M1()
{
    try
    {
        rwl.EnterWriteLock();
        needsToBeThreadSafe = RandomNumber();
    }
    finally
    {
        rwl.ExitWriteLock();
    }

}

public static void M2()
{
    try
    {
        rwl.EnterReadLock();
        print(needsToBeThreadSafe);
    }
    finally
    {
        rwl.ExitReadLock();
    }
}

Ответ 7

Для начала я согласен с ответами, используя lock(), это самый безопасный способ.

Но существует более минималистский подход, ваш пример кода показывает только одиночные утверждения с помощью needsToBeThreadSafe, и поскольку int является атомарным, вам нужно только предотвратить кэширование компилятором с помощью volatile:

class A
{
   static volatile int needsToBeThreadSafe = 0;

}

Но если вам нужно, чтобы requireToBeThreadSafe был "ThreadSafe" для нескольких операторов, используйте блокировку.