Как решить проблему с нитями, которые пытаются работать одновременно? - PullRequest
0 голосов
/ 04 апреля 2019

У меня проблема. Я сделал сервис, который отслеживает задания на печать в режиме реального времени. Это не сработало идеально, но у меня не было больших проблем. Теперь мне нужно сменить службу на программу Windows Forms. И у меня проблема с темами.

Ошибка:

System.InvalidOperationException: 'Вызывающий поток не может получить доступ к этому объекту, потому что другой поток владеет им.'

Эта ошибка появляется в строке "PrintQueue.Refresh ()".

Я не могу найти, где пытается запустить другой поток.

Я попытался установить другой поток и запустить его с помощью процедуры MonitoringJobs (), но он не работает.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using System.Collections.Concurrent;
using System.Data.SqlClient;
using System.Diagnostics;
using System.ServiceProcess;
using System.Management;
using System.Windows;
using System.Printing;
using System.Configuration;
using System.Collections.Specialized;
using System.Threading;

namespace MonitoringPrintJobs
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            timer.Elapsed += GetJobs;
            timer.AutoReset = true;
            timer.Enabled = true;
        }
        System.Timers.Timer timer = new System.Timers.Timer(5);

        int writeInterval = 1000;
        int DefaultWriteInterval = 1000;
        bool Logging;

        SelectPrinter fSelectPrinter = new SelectPrinter();

        ConcurrentDictionary<string, string> QueueJobs = new ConcurrentDictionary<string, string>();//declaration printers jobs dictionary  
        ConcurrentDictionary<string, DateTime> PrintedJobs = new ConcurrentDictionary<string, DateTime>();
        PrintServer printServer = null;
        PrintQueueCollection QueuesOnLocalServer = null;
        List<PrintQueue> queues = new List<PrintQueue>();

        public void MonitoringJobs()
        {
            //if(queues != null)
            foreach (var PrintQueue in queues)
            {
                PrintQueue.Refresh();
                using (var jobs = PrintQueue.GetPrintJobInfoCollection())//wait until collection updates!!!
                    foreach (var job in jobs)
                    {
                        if (!QueueJobs.ContainsKey(job.Name))//if list with printer jobs doesn't contain found job (name) 
                        {//then put name in list with printer jobs
                            QueueJobs.TryAdd(job.Name, job.JobStatus.ToString());
                            if (Logging == true)
                            {
                                File.AppendAllText(@"D:\Logs\Logging.txt", String.Format("{0} - {1} - {2}{3}", DateTime.Now, job.Name, job.JobStatus, Environment.NewLine));
                            }
                        }
                        else//if list with printer jobs contains found job name 
                        {
                            if (QueueJobs[job.Name] != job.JobStatus.ToString() && !QueueJobs[job.Name].ToLower().Contains("error"))//if status for this job doesn't exist
                            {
                                QueueJobs[job.Name] = job.JobStatus.ToString();//replace job's status
                                if (Logging == true)
                                {
                                    File.AppendAllText(@"D:\Logs\Logging.txt", String.Format("{0} - {1} - {2}{3}", DateTime.Now, job.Name, job.JobStatus, Environment.NewLine));
                                }
                            }
                            if (job.JobStatus.ToString().ToLower().Contains("error") && PrintedJobs.ContainsKey(job.Name))
                            {
                                var someVar = new DateTime();
                                PrintedJobs.TryRemove(job.Name, out someVar);
                            }
                        }

                        if (QueueJobs[job.Name].ToLower().Contains("print") && !QueueJobs[job.Name].ToLower().Contains("error"))//if successfully printed
                        {
                            PrintedJobs.TryAdd(job.Name, DateTime.Now);
                        }
                    }
            }
        }

        private void GetJobs(Object source, System.EventArgs e)
        {
            writeInterval--;

            MonitoringJobs();

            if (writeInterval <= 0)
            {
                writeInterval = DefaultWriteInterval;
                PrintedJobs.Clear();
                QueueJobs.Clear();
            }
        }

        protected void OnStart()
        {
            QueuesOnLocalServer = printServer.GetPrintQueues();
            writeInterval = 120000;
            foreach (var item in fSelectPrinter.SelectetPrinters)
                Logging = true;

            foreach (var printer in fSelectPrinter.SelectetPrinters)
            {
                if (string.IsNullOrEmpty(printer))
                {
                    timer.Stop();
                    Environment.Exit(0);
                }

                var queue = QueuesOnLocalServer.FirstOrDefault(o => o.FullName.ToUpper() == printer.ToUpper());

                if (queue == null)
                {
                    timer.Stop();
                    Environment.Exit(0);
                }

                queues.Add(queue);
            }

            timer.Start();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            fSelectPrinter.ShowDialog();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            printServer = new PrintServer();
            foreach (PrintQueue pq in printServer.GetPrintQueues())
                fSelectPrinter.listBox1.Items.Add(pq.Name);
        }

        private void button1_Click_1(object sender, EventArgs e)
        {
            bool StartPrinting = button2.Enabled = false;//turn of select printers form button
            if (StartPrinting == false)//StartPrinting == monitoring ==  true
            {
                OnStart();
            }
            else
            {
                StartPrinting = true;//StartPrinting == monitoring == false
                timer.Stop();
            }
        }
    }
}

В этой программе я пытался получить статусы заданий на печать и вывести их в listbox1 и записать результаты со строкой. Формат в файле.

1 Ответ

0 голосов
/ 04 апреля 2019

В событии Form1_Load вы добавляете вещи в свой fSelectedPrinter.Listbox. Если вы добавляете элементы из другого потока, это приведет к ошибке. Только поток пользовательского интерфейса может обновлять объекты в форме без использования SynchornizationContext.

   private readonly SynchronizationContext synchronizationContext;

   InitializeComponent();
   synchronizationContext = SynchronizationContext.Current;

Вот пример:

   private async void btnListFiles1_Click(object sender, EventArgs e)
  {

     if (txtDirectory1.Text == "")
     {
       MessageBox.Show(InfoDialog.SELECT_DIRECTORY,PROGRAM_NAME);
        return;
     }

     if (!Directory.Exists(txtDirectory1.Text))
     {
       MessageBox.Show(InfoDialog.DIRECTORY_NOT_EXIST, PROGRAM_NAME);
        return;
     }

     try
     {
        string fileTypes = (txtFileTypes1.Text == "") ? "" : txtFileTypes1.Text;
        string[] files = Directory.GetFiles(txtDirectory1.Text.TrimEnd(),
                 (fileTypes == "") ? "*.*" : fileTypes,
                 (chkSub1.Checked) ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly);

        listBoxFiles.Items.Clear();         
        progressBar.Step = 1;
        progressBar.Value = 1;
        progressBar.Maximum = files.Length + 1;
        listBoxFiles.BeginUpdate();

        if (txtSearchPattern1.Text != "")
        {
           string searchPattern = txtSearchPattern1.Text.ToLower();

           await System.Threading.Tasks.Task.Run(() =>
           {
              foreach (string file in files)
              {
                 if (file.ToLower().Contains(searchPattern))
                 {
                    AddToListBox(file);
                 }
              }
           });

        }
        else
        {
           await System.Threading.Tasks.Task.Run(() =>
           { 
              foreach(string file in files)
              {
                 AddToListBox(file);
              }
           });
        }

        listBoxFiles.EndUpdate();
        progressBar.Value = 0;

  }


private void AddToListBox(string item)
  {
     synchronizationContext.Send(new SendOrPostCallback(o =>
     {
        listBoxFiles.Items.Add((string)o);
        progressBar.Value++;
     }), item);         
  }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...