Execute error для не синхронизированного блока кода вызван метод синхронизации объектов

Работа с Mutex C# Решение и ответ на вопрос 2355251

skyfer

7 / 6 / 4

Регистрация: 06.02.2017

Сообщений: 73

1

20.11.2018, 21:25. Показов 6162. Ответов 14

Метки mutex (Все метки)


Доброго времени суток.
Есть задача с помощью мьютексов проводить запись в файл A.txt поочередно: рядок с консоли, рядок с файла B.txt
И так до тех пор, пока не закончиться файл B.txt или пользователь не введет exit.
Проблема вот какая, после того как 2 раза отработал поток из методом PersonalWrite и один раз ProgramWrite программа крашится с ошибкой:
System.ApplicationException: «Для не синхронизированного блока кода вызван метод синхронизации объектов.»

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
class Program
    {
        static Mutex mutexObj = new Mutex();
     
        static int sizefile = 0;
        static int iter = 0;
        static string[] file;
        static void Main(string[] args)
        {
            countline();
            file = new string[sizefile];
            string text = null;
            using (StreamReader sr = new StreamReader("B.txt", System.Text.Encoding.Default))
            {
                for (int i = 0; i < file.Length; i++)
                {
                    text = sr.ReadLine();
                    file[i] = text;
                }
            }
            Thread myThread;
            
            myThread = new Thread(PersonalWrite);
            myThread.Start();
            Thread myThread2 = new Thread(ProgramWrite);
            myThread2.Start();
            
            //Console.ReadLine();
        }
 
       
        public static void PersonalWrite()
        {
            mutexObj.WaitOne();
            string text = "";
 
            do
            {
                Console.WriteLine("Enter text: (if need close programm enter 'exit')");
                text = Console.ReadLine();
                using (StreamWriter sw = new StreamWriter("A.txt", true, System.Text.Encoding.Default))
                {
                    sw.WriteLine(text);
                }
                mutexObj.ReleaseMutex();
            }
            while (text != "exit");
            return;
        }
 
        static void countline()
        {
            using (StreamReader sr = new StreamReader("B.txt", System.Text.Encoding.Default))
            {
                int nline = 0;
                while ((sr.ReadLine()) != null)
                {
                    nline++;
                }
                sizefile = nline;
            }
        }
 
 
        public static void ProgramWrite()
        {
            mutexObj.WaitOne();
 
            string text = file[iter];
            
            using (StreamWriter sw = new StreamWriter("A.txt", true, System.Text.Encoding.Default))
            {
                sw.WriteLine(text);
                iter++;
            }
            mutexObj.ReleaseMutex();
        }
 
       
    }

кто подскажет каким образом можно исправить?

__________________
Помощь в написании контрольных, курсовых и дипломных работ, диссертаций здесь



0



Programming

Эксперт

94731 / 64177 / 26122

Регистрация: 12.04.2006

Сообщений: 116,782

20.11.2018, 21:25

Ответы с готовыми решениями:

Работа с mutex
Господа, есть такая проблема. Нужно реализовать многопоточность при помощи mutex. Должны быть 3…

Работа с Mutex
Доброго дня суток!

Решил блокировать доступ к файлу для разных потоков через Mutex, что то не…

mutex
День добрый. Прошу объяснить мне дураку

m_hShared = OpenMutex(MUTEX_ALL_ACCESS, TRUE,…

Mutex
#include &lt;iostream&gt;
#include &lt;windows.h&gt;
#include &lt;iostream&gt;
#include &lt;fstream&gt;
#include…

14

0 / 0 / 0

Регистрация: 06.10.2014

Сообщений: 27

21.11.2018, 15:34

2

Пиши на плюсах. Там все получиться



0



Эксперт .NET

16930 / 12507 / 3286

Регистрация: 17.09.2011

Сообщений: 20,745

23.11.2018, 19:42

3

skyfer, вы мьютекс захватываете один раз перед циклом, а освободить пытаетесь на каждой итерации, отсюда и ошибка.

Gartus13, ну спасибо хоть винду переустановить или вообще линупс поставить не предложили.



1



skyfer

7 / 6 / 4

Регистрация: 06.02.2017

Сообщений: 73

23.11.2018, 23:07

 [ТС]

4

Спасибо за совет, теперь не вылетает. Но не все так, как хотелось бы. Программа может записать пару рядков из файла, иили писать может явно не из начала файла B. Каким образом сделать так, чтобы строго запись была по 1 рядку поочередно и с файла, и с консоли?
Подправленный код предоставляю опять.

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
class Program
    {
        static Mutex mutexObj = new Mutex();
     
        static void Main(string[] args)
        {
            Thread myThread = new Thread(PersonalWrite); 
            myThread.Start();
            myThread = new Thread(ProgramWrite); 
            myThread.Start();
        }
 
       
        public static void PersonalWrite()
        {
            string text = "";
            while (true)
            {
                mutexObj.WaitOne();
                Console.WriteLine("Enter text: (if need close programm enter 'exit')");
                text = Console.ReadLine();
                if(text == "exit")
                    return;
                using (StreamWriter sw = new StreamWriter("A.txt", true, System.Text.Encoding.Default))
                {
                    sw.WriteLine(text);
                }
                mutexObj.ReleaseMutex();
            }
            
        }
 
        public static void ProgramWrite()
        {
            using (StreamReader sr = new StreamReader("B.txt", System.Text.Encoding.Default))
            {
                while ((sr.ReadLine()) != null)
                {
                    mutexObj.WaitOne();
                    using (StreamWriter sw = new StreamWriter("A.txt", true, System.Text.Encoding.Default))
                    {
                        sw.WriteLine(sr.ReadLine());
                    }
                    mutexObj.ReleaseMutex();
 
                }
            }
        }
}



0



Эксперт .NET

16930 / 12507 / 3286

Регистрация: 17.09.2011

Сообщений: 20,745

23.11.2018, 23:33

5

skyfer, вам для этого нужно два мьютекса — назовем их Х и У (мьютекс Й пока не нужен).
На каждой итерации каждый поток будет ожидать один мьютекс и освобождать другой: поток 1 ждет мьютекс Х и после записи освобождает мьютекс У. Поток 2 ждет мьютекс У и после записи освобрждает мьютекс Х.
При инициализации один мьютекс должен создаваться занятым, а другой — свободным. Какой где — зависит от того, какой поток должен писать первым: консольный или текстовый.
Тот, который начинает, должен изначально иметь свободный мьютекс.



0



7 / 6 / 4

Регистрация: 06.02.2017

Сообщений: 73

24.11.2018, 00:20

 [ТС]

6

а каким образом создать занятый мьютекс? а то в материалах, которые я читал там не сказано именно про занятость мьютекса, и гугл не особо понимает то.

Добавлено через 26 минут
Если я правильно понимаю, то «занять» т.е. блокировать — WaitOne(). Но таким образом теряется синхронизация



0



Эксперт .NET

16930 / 12507 / 3286

Регистрация: 17.09.2011

Сообщений: 20,745

24.11.2018, 00:26

7

skyfer, у мьютекса есть конструктор, в который можно передать boolean.
Синхронизация не теряется.



0



skyfer

7 / 6 / 4

Регистрация: 06.02.2017

Сообщений: 73

24.11.2018, 00:46

 [ТС]

8

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

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
class Program
    {
        static Mutex mutexObj1 = new Mutex(false);
        static Mutex mutexObj2 = new Mutex(true);
 
        static void Main(string[] args)
        {
            Thread myThread = new Thread(PersonalWrite); 
            myThread.Start();
            myThread = new Thread(ProgramWrite); 
            myThread.Start();
        }
 
       
        public static void PersonalWrite()
        {
            string text = "";
            while (true)
            {
                mutexObj2.WaitOne();
                Console.WriteLine("Enter text: (if need close programm enter 'exit')");
                text = Console.ReadLine();
                if(text == "exit")
                    return;
                using (StreamWriter sw = new StreamWriter("A.txt", true, System.Text.Encoding.Default))
                {
                    sw.WriteLine(text);
                }
                mutexObj1.ReleaseMutex();
            }
            
        }
 
        public static void ProgramWrite()
        {
            using (StreamReader sr = new StreamReader("B.txt", System.Text.Encoding.Default))
            {
                while ((sr.ReadLine()) != null)
                {
                    mutexObj1.WaitOne();
                    using (StreamWriter sw = new StreamWriter("A.txt", true, System.Text.Encoding.Default))
                    {
                        sw.WriteLine(sr.ReadLine());
                    }
                    mutexObj2.ReleaseMutex();
                }
            }
        }
    }



0



Эксперт .NET

16930 / 12507 / 3286

Регистрация: 17.09.2011

Сообщений: 20,745

24.11.2018, 11:04

9

skyfer, не создавайте два потока (StreamWriter) для записи в финальный файл.
Создайте один и пишите в него из обоих методов.
С синхронизацией.



0



skyfer

7 / 6 / 4

Регистрация: 06.02.2017

Сообщений: 73

24.11.2018, 12:22

 [ТС]

10

Вроде все сделал в соответствии с вашими рекомендациями, но проблема из синхронизацией осталась.

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
class Program
    {
        static Mutex mutexObj1 = new Mutex(true);
        static Mutex mutexObj2 = new Mutex(false);
        static StreamWriter streamWriter = new StreamWriter("A.txt", false, System.Text.Encoding.Default);
        static void Main(string[] args)
        {
            Thread myThread = new Thread(PersonalWrite);
            myThread.Start();
            myThread = new Thread(ProgramWrite);
            myThread.Start();
        }
        
 
        public static void PersonalWrite()
        {
            string text = "";
            while (true)
            {
                mutexObj1.WaitOne();
                Console.WriteLine("Enter text: (if need close programm enter 'exit')");
                text = Console.ReadLine();
                if(text == "exit")
                    return;
                streamWriter.WriteLine(text);
                mutexObj2.ReleaseMutex();
            }
            
        }
 
        public static void ProgramWrite()
        {
            using (StreamReader sr = new StreamReader("B.txt", System.Text.Encoding.Default))
            {
                while ((sr.ReadLine()) != null)
                {
                    mutexObj2.WaitOne();
                    streamWriter.WriteLine(sr.ReadLine());
                    mutexObj1.ReleaseMutex();//"Для не синхронизированного блока кода вызван метод синхронизации объектов."
                }
            }
        }
    }

если я правильно понимаю, то предварительно метод PersonalWrite() блокирует mutexObj1, а потом уже метод ProgramWrite() его освобождает.Формально синхронизация присутствует, либо я чего то не понимаю.



0



Psilon

Master of Orion

Эксперт .NET

6094 / 4950 / 905

Регистрация: 10.07.2011

Сообщений: 14,522

Записей в блоге: 5

25.11.2018, 05:57

11

skyfer, странная задача, мьютексы тут вообще не нужны

Я бы написал как-то так (задача отменяется по обычному сочетанию клавиш ctrl+C):

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
void Main()
{
    var cts = new CancellationTokenSource();
 
    Console.CancelKeyPress += (_, ccea) =>
    {
        cts.Cancel();
        ccea.Cancel = true;
    };
    Task.Run(() =>
    {
        var lines = ConcatLines(
                   File.ReadLines(@"C:UserspzixeDesktop1.txt"), 
                   File.ReadLines(@"C:UserspzixeDesktop2.txt"));
        foreach (var line in lines)
        {
            if (cts.IsCancellationRequested)
            {
                return;
            }
            Console.WriteLine(line);
        }
        cts.Cancel();
    });
    
    cts.Token.WaitHandle.WaitOne();
}
 
IEnumerable<string> ConcatLines(IEnumerable<string> fileA, IEnumerable<string> fileB) => 
    fileA.Zip(fileB, (a, b) => new[] {a, b}).SelectMany(x => x);



0



7 / 6 / 4

Регистрация: 06.02.2017

Сообщений: 73

25.11.2018, 10:53

 [ТС]

12

к сожалению постановка задачи именно с использованием мьютексов



0



Master of Orion

Эксперт .NET

6094 / 4950 / 905

Регистрация: 10.07.2011

Сообщений: 14,522

Записей в блоге: 5

25.11.2018, 11:40

13

Добавьте в начало `Mutex mutexObj1 = new Mutex(true);`



0



Anklav

447 / 305 / 47

Регистрация: 23.01.2013

Сообщений: 661

25.11.2018, 13:17

14

Лучший ответ Сообщение было отмечено skyfer как решение

Решение

Проблема в том, что вы берете Mutex одним потоком, а освобождаете другим. Вам вообще нужно 2 мьютекса? Может вам подойдет один мьютекс + переменная?

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
    private enum Worker
    {
      Console,
      File,
      Main
    }
 
    private class ThreadState
    {
      public StreamWriter FileA { get; private set; }
      public Mutex Mutex { get; private set; }
      public Worker CurrentWorker { get; set; }
 
      public ThreadState(StreamWriter fileA, Mutex mutex)
      {
        FileA = fileA;
        Mutex = mutex;
        CurrentWorker = Worker.Console;
      }
    }
    
    private static Thread _consoleThread;
    private static Thread _fileThread;
 
    static void Main()
    {
      using (var writer = new StreamWriter(@"D:A.txt", false, System.Text.Encoding.Default))
      {
        var mutex = new Mutex(false);
        var state = new ThreadState(writer, mutex);
 
        _consoleThread = new Thread(ConsoleWrite);
        _consoleThread.IsBackground = true;
        _consoleThread.Start(state);
 
        _fileThread = new Thread(FileWrite);
        _fileThread.IsBackground = true;
        _fileThread.Start(state);
 
        while (true)
        {
          state.Mutex.WaitOne();
          try
          {
            if (state.CurrentWorker == Worker.Main)
              return;
          }
          finally
          {
            state.Mutex.ReleaseMutex();
          }
        }
      }
    }
 
    private static void ConsoleWrite(object state)
    {
      var threadState = (ThreadState)state;
      while (true)
      {
        threadState.Mutex.WaitOne();
        try
        {
          if (threadState.CurrentWorker == Worker.Console)
          {
            var line = Console.ReadLine();
            if (line == "exit")
            {
              threadState.CurrentWorker = Worker.Main;
              return;
            }
              
            threadState.FileA.WriteLine(line);
            threadState.CurrentWorker = Worker.File;
          }
        }
        finally
        {
          threadState.Mutex.ReleaseMutex();
        }
      }
    }
 
    private static void FileWrite(object state)
    {
      var threadState = (ThreadState)state;
      using (var reader = File.OpenText(@"D:B.txt"))
      {
        while (true)
        {
          threadState.Mutex.WaitOne();
          try
          {
            if (threadState.CurrentWorker == Worker.File)
            {
              var line = reader.ReadLine();
              if (line == null)
              {
                threadState.CurrentWorker = Worker.Main;
                return;
              }
 
              threadState.FileA.WriteLine(line);
              threadState.CurrentWorker = Worker.Console;
            }
          }
          finally
          {
            threadState.Mutex.ReleaseMutex();
          }
        }
      }
    }



0



7 / 6 / 4

Регистрация: 06.02.2017

Сообщений: 73

25.11.2018, 15:07

 [ТС]

15

Большое спасибо! Решение оказалось немного большим, чем я предполагал изначально, но все замечательно работает.



0



IT_Exp

Эксперт

87844 / 49110 / 22898

Регистрация: 17.06.2006

Сообщений: 92,604

25.11.2018, 15:07

Помогаю со студенческими работами здесь

Mutex
Есть код, вида:

public static Mutex mut = new Mutex();
public static void…

Mutex in Linux
Добрый день.

Допустим есть код

void func () {
pthread_mutex_lock(&amp;mutexConsole);

Многопоточность и Mutex
Мне помогли написать код который ищет максимум многопоточно, и посоветовали сделать поиск…

Проблемы с <mutex>
Всем привет. Приступил я, значит, к изучению многопоточности в плюсах. И, как и все, дошел до темы…

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:

15

Я нашел проблему. Сначала несколько вещей о классе filterCtiCallLog. Я разработал его так, чтобы работать как асинхронно, так и синхронно. Для первого я написал код для асинхронного выполнения. Мне нужен способ инициировать события из потока дочерних работников родителям, чтобы сообщить о рабочем состоянии. Для этого я использовал AsyncOperation класс и метод post. Вот часть кода для запуска события CtiCallsRetrieved.

public class FilterCtiCallLog
{
    private int RequestCount = 0;
    private AsyncOperation createCallsAsync = null;
    private SendOrPostCallback ctiCallsRetrievedPost;
    public void CreateFilteredCtiCallLogSync()
    {
        createCallsAsync = AsyncOperationManager.CreateOperation(null);
        ctiCallsRetrievedPost = new SendOrPostCallback(CtiCallsRetrievedPost);
        CreateFilteredCtiCallLog();
    }

    private void CreateFilteredCtiCallLog()
    {
        int count=0;
        //do the job
        //............
        //...........
        //Raise the event
        createCallsAsync.Post(CtiCallsRetrievedPost, new CtiCallsRetrievedEventArgs(count));
        //...........
        //...........
    }

    public event EventHandler<CtiCallsRetrievedEventArgs> CtiCallsRetrieved;

    private void CtiCallsRetrievedPost(object state)
    {
        CtiCallsRetrievedEventArgs args = state as CtiCallsRetrievedEventArgs;
        if (CtiCallsRetrieved != null)
            CtiCallsRetrieved(this, args);
    }
}

Как вы видите, код выполняется синхронно. Проблема здесь в методе AsyncOperation.Post(). Я предположил, что если он вызывается в основном потоке, он будет действовать как просто запуск события, а не размещение его в родительский поток. Однако это было не так. Я не знаю, как он работает, но я изменил код, чтобы проверить, называется ли CreateFilteredCtiCallLog синхронизацией или асинхронным. И если это асинхронный вызов, я использовал метод AsyncOperation.Post, если нет, я просто вызвал EventHandler, если он не null. Вот скорректированный код

public class FilterCtiCallLog
{
    private int RequestCount = 0;
    private AsyncOperation createCallsAsync = null;
    private SendOrPostCallback ctiCallsRetrievedPost;
    public void CreateFilteredCtiCallLogSync()
    {
        createCallsAsync = AsyncOperationManager.CreateOperation(null);
        ctiCallsRetrievedPost = new SendOrPostCallback(CtiCallsRetrievedPost);
        CreateFilteredCtiCallLog(false);
    }

    private void CreateFilteredCtiCallLog(bool isAsync)
    {
        int count=0;
        //do the job
        //............
        //...........
        //Raise the event
        RaiseEvent(CtiCallsRetrievedPost, new CtiCallsRetrievedEventArgs(count),isAsync);
        //...........
        //...........
    }

    public event EventHandler<CtiCallsRetrievedEventArgs> CtiCallsRetrieved;

    private void RaiseEvent(SendOrPostCallback callback, object state, bool isAsync)
    {
        if (isAsync)
            createCallsAsync.Post(callback, state);
        else
            callback(state);
    }

    private void CtiCallsRetrievedPost(object state)
    {
        CtiCallsRetrievedEventArgs args = state as CtiCallsRetrievedEventArgs;
        if (CtiCallsRetrieved != null)
            CtiCallsRetrieved(this, args);
    }
}

Спасибо всем за ответы!

Исключение: метод синхронизации объектов был вызван из несинхронизированного блока кода.

У меня есть несколько потоков, которые пишут в один и тот же int. Каждый поток увеличивает целочисленное значение. Каков простой способ синхронизировать операцию приращения. Оператор блокировки работает только с объектом, поэтому я не могу его использовать. Я пробовал также следующее:

static int number=0;

static void Main(string[] args)
    {
        ThreadStart ts = new ThreadStart(strtThread);
        new Thread(ts).Start();
        new Thread(ts).Start();
        new Thread(ts).Start();
        new Thread(ts).Start();
        new Thread(ts).Start();
        new Thread(ts).Start();
        Console.ReadLine();
    }

    public static void strtThread()
    {
        bool lockTaken = false;

        Monitor.Enter(number,ref lockTaken);
        try
        {
            Random rd = new Random();
            int ee = rd.Next(1000);
            Console.WriteLine(ee);
            Thread.Sleep(ee);
            number++;
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
        finally 
        {
            if (lockTaken)
            {
             Monitor.Exit(number);
            }

        }
    }

Это дает мне следующую ошибку:

Метод синхронизации объектов был вызван из несинхронизированного блока кода.

Вы можете использовать Метод Interlocked.Increment для автоматического увеличения целого числа без блокировки:

public static void strtThread()
{
    Interlocked.Increment(ref number);
}

Если у вас несколько операторов, вы можете создать объект пример, что вы можете Блокировка:

private static int number = 0;
private static readonly object gate = new object();

public static void strtThread()
{
    lock (gate)
    {
       number++;
    }    
}

Создан 23 ноя.

Зачем тебе возиться с number? Думаю, в этом проблема. Попробуй это:

static Object locking = new Object();

static void Main(string[] args)
    {
        ThreadStart ts = new ThreadStart(strtThread);
        new Thread(ts).Start();
        new Thread(ts).Start();
        new Thread(ts).Start();
        new Thread(ts).Start();
        new Thread(ts).Start();
        new Thread(ts).Start();
        Console.ReadLine();
    }

    public static void strtThread()
    {
        lock(locking) {
            try
            {
                Random rd = new Random();
                int ee = rd.Next(1000);
                Console.WriteLine(ee);
                Thread.Sleep(ee);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    }

Создан 23 ноя.

Блокировано. обеспечивает атомарное приращение. В Блокированный класс в общем, «предоставляет атомарные операции для переменных, которые совместно используются несколькими потоками».

Создан 23 ноя.

Не тот ответ, который вы ищете? Просмотрите другие вопросы с метками

c#
.net
multithreading
c#-4.0

or задайте свой вопрос.

Понравилась статья? Поделить с друзьями:
  • Execute command error gta san andreas
  • Exception access violation java error
  • Execjs runtime error
  • Exec init exec format error home assistant
  • Exception access violation 0xc0000005 cyberpunk 2077 как исправить