Dobrý den,
vytvářím prvně aplikaci s vlákny a nějak mi to nejde. Potřebuju udělat aplikaci, kde poběží hlavní vlákno a akorát při spuštětí aplikace a nebo po uplynutí zadaného časového intervalu se spustí druhé vlákno (pracovní), které provede určitý úkol. Potřebuju ale ještě, aby když probíhá pracovní vlákno a uživatel zmáčkne nějaké tlačítko, aby se pracovní vlákno zastavilo, hlavní vlákno zpracovalo požadavek uživatele a po jeho splnění se opět spustilo pracovní vlákno a dodělalo svůj úkol.
Jednoduchá aplikaci, na které si chci zprovoznit tuto funkčnost, než ji dám do skutečné aplikace. Pracovní vlákno se spouští pří startu a nebo po uplynutí času v Timeru1. Button2 simuluje požadavek od uživatele, má vyvolat pozastavení pracovního vlákna. Button3 simuluje splnění požadavku od uživatele a má opětovně spustit pracovní vlákno.
public partial class Form1 : Form { private int max = 100000000; Thread pracovni; public Form1() { InitializeComponent(); progressBar1.Minimum = 0; progressBar1.Maximum = max; progressBar1.Value = 0; Thread.CurrentThread.Name = "hlavni"; pracovni = new Thread(Inkrement); pracovni.Name = "pracovni"; timer1.Interval = 1000; timer1.Start(); pracovni.Start(); } void Inkrement() { int i = 0; while (i != max) { i++; progressBar1.Increment(1); // InvalidOperationException - Cross-thread operation not valid: Control 'progressBar1' accessed //from a thread other than the thread it was created on. } progressBar1.Value = 0; //restart
} private void button2_Click(object sender, EventArgs e) { MessageBox.Show("Zastav inkrementaci"); pracovni.Join(); } private void button3_Click(object sender, EventArgs e) { MessageBox.Show("Opet bez"); pracovni.Start(); } private void timer1_Tick(object sender, EventArgs e) { MessageBox.Show("Samorozjezd"); pracovni.Start(); } }
Problém je v metodě Inkrement. Když dojde k úpravě hodnoty Value progressBar1, vyskočí vyjímka uvedená v zakomentované části pod progressBar1.Increment(1);
Chápu, že nemůžu z pracovního vlákna volat objekt vytvořený v hlavním vláknu. Zkoušel jsem kód upravit s pomocí delegátů, ale poté program funguje tak, že proběhne Inkrement až do konce a nejde stisknout žádné tlačítko a Inkrementaci přerušit. Ještě jsem musel odstranit Timer, protože pak mi jen vyskakovalo okno, že došlo k samospuštění a program skončil vyjimkou, když chtěl upravovat Value progressBar1.
Kód s delegátem:
public partial class Form1 : Form
{
private int max = 1000000;
Thread pracovni;
public Form1()
{
InitializeComponent();
progressBar1.Minimum = 0;
progressBar1.Maximum = max;
progressBar1.Value = 0;
Thread.CurrentThread.Name = "hlavni";
pracovni = new Thread(new ThreadStart(Inkrement));
pracovni.Name = "pracovni";
pracovni.Start();
}
protected delegate void SetIntDelegate(int cislo);
protected void SetInt(int cislo)
{
progressBar1.Value=cislo;
}
void Inkrement()
{
lock (this)
{
int i = 0;
while (i != max)
{
i++;
BeginInvoke(new SetIntDelegate(SetInt), new object[] { i });
}
}
progressBar1.Value = 0;
}
private void button2_Click(object sender, EventArgs e)
{
if (pracovni.ThreadState == ThreadState.Running)
{
MessageBox.Show("Zastav inkrementaci");
pracovni.Join();
}
}
private void button3_Click(object sender, EventArgs e)
{
if (pracovni.ThreadState == ThreadState.WaitSleepJoin)
{
MessageBox.Show("Opet bez");
pracovni.Start();
}
}
}
Byl bych moc vděčný za radu, jak to napsat, aby to fungovalo podle mých potřeb. Děkuji moc
A ještě bych se chtěl zeptat, jestli je dobrý způsob pozastavení pracovního vlákna metodou pracovni.Join();?
Děkuji moc