Все технические форумы на одном сайте Удобный поиск информации с популярных форумов в одном месте
Вопрос: Некорректно передаются параметры в поток

Возникла проблема : при создании потоков в 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
using System;
using System.Diagnostics;
using System.Threading;
using System.Collections.Generic;  
 
namespace matrix_tests
{
    public class Counter
    {
        public int i;
        public int j;
        public int n;
    }
 
 
        class Program
    {
        public static int A = 3;
        public static int B = 4;
        public static int C = 5;
 
        public static void Count(object obj) 
            {
                Counter param = (Counter)obj;
 
               Console.WriteLine("Поток : {3} ; Получен параметр i = {0},j = {1},n = {2}", param.i, param.j, param.n, Thread.CurrentThread.Name);
            }
 
            static void Main(string[] args)
        {
                Counter counter = new Counter();
 
                
                int countThread = 0;
 
                Stopwatch stopWatch = new Stopwatch();
                stopWatch.Start();
 
 
                List<Thread> threads = new List<Thread>();
                
 
 
                for (int i1 = 0; i1 < A; i1++)
                {
                    for (int j1 = 0; j1 < B; j1++)
                    {
                    counter.i = i1;
                    counter.j = j1;
                    counter.n = C;
                    threads.Add(new Thread(new ParameterizedThreadStart(Count))
                        {
                            Name = "Thread=" + i1 + "x" + j1,
 
                        });
                        Console.WriteLine("Поток : {3}, номер потока {4} ; Передается параметр i = {0},j = {1},n = {2}", i1, j1, counter.n, threads[countThread].Name, countThread);
                        threads[countThread].Start(counter);
                        countThread++;
                      
                    }
                }
 
                Console.WriteLine("Всего создано процессов : {0}", countThread);
 
                stopWatch.Stop();
 
 
                TimeSpan ts = stopWatch.Elapsed;
                
 
                string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
                    ts.Hours, ts.Minutes, ts.Seconds,
                    ts.Milliseconds / 10);
                Console.WriteLine("RunTime for calc mass with Thread " + elapsedTime);
 
            Console.ReadLine();
 
        }
    }
}
Ниже результат. Ка видно в поток уходят (...Передается параметр...) корректные данные (меняются в зависимости от итерации циклов параметры i и j . Но в потоке (.. Получен параметр...)почему-то показаны другие значения.

Результат :
Поток : Thread=0x0, номер потока 0 ; Передается параметр i = 0,j = 0,n = 5
Поток : Thread=0x0 ; Получен параметр i = 0,j = 0,n = 5
Поток : Thread=0x1, номер потока 1 ; Передается параметр i = 0,j = 1,n = 5
Поток : Thread=0x2, номер потока 2 ; Передается параметр i = 0,j = 2,n = 5
Поток : Thread=0x1 ; Получен параметр i = 0,j = 2,n = 5
Поток : Thread=0x3, номер потока 3 ; Передается параметр i = 0,j = 3,n = 5
Поток : Thread=0x2 ; Получен параметр i = 0,j = 3,n = 5
Поток : Thread=0x3 ; Получен параметр i = 0,j = 3,n = 5
Поток : Thread=1x0, номер потока 4 ; Передается параметр i = 1,j = 0,n = 5
Поток : Thread=1x1, номер потока 5 ; Передается параметр i = 1,j = 1,n = 5
Поток : Thread=1x0 ; Получен параметр i = 1,j = 1,n = 5
Поток : Thread=1x2, номер потока 6 ; Передается параметр i = 1,j = 2,n = 5
Поток : Thread=1x3, номер потока 7 ; Передается параметр i = 1,j = 3,n = 5
Поток : Thread=1x2 ; Получен параметр i = 1,j = 3,n = 5
Поток : Thread=1x1 ; Получен параметр i = 1,j = 3,n = 5
Поток : Thread=1x3 ; Получен параметр i = 1,j = 3,n = 5
Поток : Thread=2x0, номер потока 8 ; Передается параметр i = 2,j = 0,n = 5
Поток : Thread=2x1, номер потока 9 ; Передается параметр i = 2,j = 1,n = 5
Поток : Thread=2x0 ; Получен параметр i = 2,j = 1,n = 5
Поток : Thread=2x2, номер потока 10 ; Передается параметр i = 2,j = 2,n = 5
Поток : Thread=2x1 ; Получен параметр i = 2,j = 2,n = 5
Поток : Thread=2x3, номер потока 11 ; Передается параметр i = 2,j = 3,n = 5
Всего создано процессов : 12
RunTime for calc mass with Thread 00:00:00.48
Поток : Thread=2x2 ; Получен параметр i = 2,j = 3,n = 5
Поток : Thread=2x3 ; Получен параметр i = 2,j = 3,n = 5
Ответ: Спасибо, теперь работает корректно.

Переместил объявление экземпляра (Counter counter = new Counter() во внутренний цикл.

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
for (int i1 = 0; i1 < A; i1++)
                {
                    for (int j1 = 0; j1 < B; j1++)
                    {
                    Counter counter = new Counter();
                    counter.i = i1;
                    counter.j = j1;
                    counter.n = C;
                    threads.Add(new Thread(new ParameterizedThreadStart(Count))
                        {
                            Name = "Thread=" + i1 + "x" + j1,
 
                        });
                        Console.WriteLine("Поток : {3}, номер потока {4} ; Передается параметр i = {0},j = {1},n = {2}", i1, j1, counter.n, threads[countThread].Name, countThread);
                        threads[countThread].Start(counter);
                        countThread++;
                      
                    }
                }
Вопрос: Потоки

Код Java(TM) 2 Platform Standard Edition 5.0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class NewThread implements Runnable {
    String name;
    Thread t;
 
    NewThread(String threadname) {
        name = threadname;
        t = new Thread(this, name);
        t.start();
    }
 
    public void run() {
        try {
            for (int i = 5; i > 0; i--) {
                System.out.println("Дочерний поток: " + i);
                Thread.sleep(1000);
            }
        } catch (InterruptedException e) {
            System.out.println("Дочерний поток прерван");
        }
    }
}
Код Java(TM) 2 Platform Standard Edition 5.0
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
public class ThreadDemo {
    public static void main(String args[]) {
        NewThread ob1 = new NewThread("Один");
        NewThread ob2 = new NewThread("Два");
        NewThread ob3 = new NewThread("Три");
 
        System.out.println("Поток Один запущен: " + ob1.t.isAlive());
        System.out.println("Поток Два запущен: " + ob2.t.isAlive());
        System.out.println("Поток Три запущен: " + ob3.t.isAlive());
 
        try {
            System.out.println("Ожидание завершения потоков.");
            ob1.t.join();
            ob2.t.join();
            ob3.t.join();
        } catch (InterruptedException e) {
            System.out.println("Главный поток прерван");
        }
 
        System.out.println("Поток Один запущен: " + ob1.t.isAlive());
        System.out.println("Поток Два запущен: " + ob2.t.isAlive());
        System.out.println("Поток Три запущен: " + ob3.t.isAlive());
 
        System.out.println("Главный поток завершен");
    }
}
Почему потоки начинают выполняться после строки System.out.println("Ожидание завершения потоков.");, а не после вызова конструкторов?
Ответ: У меня так выводит
Кликните здесь для просмотра всего текста

Дочерний поток: 5
Дочерний поток: 5
Дочерний поток: 5
Поток Один запущен: true
Поток Два запущен: true
Поток Три запущен: true
Ожидание завершения потоков.
Дочерний поток: 4
Дочерний поток: 4
Дочерний поток: 4
Дочерний поток: 3
Дочерний поток: 3
Дочерний поток: 3
Дочерний поток: 2
Дочерний поток: 2
Дочерний поток: 2
Дочерний поток: 1
Дочерний поток: 1
Дочерний поток: 1
Поток Один запущен: false
Поток Два запущен: false
Поток Три запущен: false
Главный поток завершен

Без sleep каждый раз по разному.
Вопрос: Потоки! Как сделать работу потоков по очереди?

Всем привет! Помогите разобраться!

Дано: 5 потоков, они генерят по очереди сообщения.

Java
1
2
3
4
5
6
7
8
9
public class Main {
    public static void main(String[] args) {
        for (int i = 1; i < 6; i++){
            Thread t = new Thread(new Producer());
            t.setName("Поток "+ i);
            t.start();
        }
    }
}
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Producer implements Runnable {
    private static int i = 0;
    public synchronized  void run() {
        while(true){
            i++;
            try {
                System.out.println(Thread.currentThread().getName() + " создано сообщение № " + i);
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
Вывод:

Кликните здесь для просмотра всего текста
Поток 1 создал сообщение № 1
Поток 2 создал сообщение № 2
Поток 3 создал сообщение № 3
Поток 4 создал сообщение № 4
Поток 5 создал сообщение № 5
Поток 1 создал сообщение № 6
Поток 2 создал сообщение № 7
Поток 3 создал сообщение № 8
Поток 4 создал сообщение № 9
Поток 5 создал сообщение № 10
Поток 1 создал сообщение № 11
Поток 5 создал сообщение № 12
Поток 4 создал сообщение № 13
Поток 2 создал сообщение № 14
Поток 3 создал сообщение № 15
....


А теперь сам вопрос: как можно сделать, что бы потоки всегда работали по очереди и по возрастанию? Т.е. сначала 1, потом 2, потом 3 и тд.
Т.е. вывод должен быть всегда такой (не зависимо от кол-ва потоков):

Кликните здесь для просмотра всего текста
Поток 1 создал сообщение № 1
Поток 2 создал сообщение № 2
Поток 3 создал сообщение № 3
Поток 4 создал сообщение № 4
Поток 5 создал сообщение № 5
Поток 1 создал сообщение № 6
Поток 2 создал сообщение № 7
Поток 3 создал сообщение № 8
Поток 4 создал сообщение № 9
Поток 5 создал сообщение № 10
Поток 1 создал сообщение № 11
Поток 2 создал сообщение № 12
Поток 3 создал сообщение № 13
Поток 4 создал сообщение № 14
Поток 5 создал сообщение № 15
...
Ответ: MaxXxon,
Сообщение от KEKCoGEN
если вам нужно чтобы потоки работали по очереди, зачем вам вообще потоки тогда?
Присоединяюсь к вопросу
Вопрос: Программная реализация простого бесприоритетного планировщика потоков

Доброе утро всем!
Нужна Ваша помощь в доработке. Была задача:
Программная реализация простого бесприоритетного планировщика потоков.
Исходные данные:
- возможные состояния потоков: выполнение, ожидание, блокировка
- отрабатываемые события: создание нового потока, завершение активного потока, завершение кванта времени у активного потока, блокирование потока, разблокирование потока
- основная структура данных: адресный (связный) список дескрипторов потоков с двумя полями - идентификатор потока, состояние потока
- поведение списка: классическая очередь с добавлением в конец и извлечением из начала
- язык реализации - C++ Builder XE8.

Сделала так:
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
//---------------------------------------------------------------------------
 
#include <vcl.h>
#pragma hdrstop
 
#include "Unit1.h"
#include "math.h"
 
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
 
class myThread:public TThread
{
protected:
   void __fastcall Execute();
   void __fastcall run();
public:
   __fastcall myThread(int n, bool CreateSuspended);
   int type;
};
 
enum stady{run,wait,blok};
 
DWORD WINAPI MyThread(int pot);
 
struct fifo{
struct fifo *next;
DWORD tID;
stady tStady;
};
 
 fifo *first;
 fifo *last;
 fifo *current;
 int count;
 bool started = false;
 int timeKuant = 1000;
 String st;
 
HANDLE hThread;
DWORD ThreadID;
 
DWORD WINAPI ThreadFunc(LPVOID param)
{
int i = 0;
  for(;;){
   i++;
   if(i>32000) i = 0;
  }
}
 
int AddThread(){
 
fifo *Tmp = new fifo;
 
hThread=CreateThread(NULL,0,ThreadFunc,0,CREATE_SUSPENDED,&ThreadID);
 
if (hThread!=NULL){
Tmp->next = NULL;
Tmp->tID = ThreadID;
Tmp->tStady=wait;
 
last->next=Tmp;
last=Tmp;
count=count+1;
return ThreadID;} else
{return -1;}
}
 
bool DelThread(){
if (count>0){
fifo *Tmp = first->next;
first->next=Tmp->next;
count=count-1;
if(count==0) {last=first;}
delete Tmp;
return true;} else
{return false;}
 
}
DWORD WINAPI StartPlan(LPVOID param) {
 
started = true;
current = first->next;
while (started&(count>0)) {
 
// запуск текущего потока
if(current->tStady!=blok)
   {
    int ThreadID=current->tID;
    hThread = OpenThread(THREAD_ALL_ACCESS,FALSE, ThreadID);
    if (hThread != NULL)
    {
     current->tStady=run;
     ResumeThread(hThread); // Запуск потока
     st="Работает поток "+IntToStr(ThreadID)+"... ";
     WaitForSingleObject(hThread,timeKuant);
     // Приостановка текущего потока
 
     SuspendThread(hThread);
     current->tStady=wait;
     }
    }
 
    if (current->next==NULL)
        {current = first->next;}
     else {current=current->next;}
}
}
 
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
   fifo *Tmp = new fifo;
 
   Tmp->next = NULL;
   Tmp->tID = 0;
   Tmp->tStady=blok;
   first=Tmp;
   last=Tmp;
 
}
//---------------------------------------------------------------------------
 
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
if(st!=""){Memo1->Lines->Add(st);st="";}
}
//---------------------------------------------------------------------------
 
void __fastcall TForm1::Button1Click(TObject *Sender)
{
int nThreadID=AddThread();
 if (nThreadID>0){Memo1->Lines->Add("Поток "+IntToStr(nThreadID)+" создан и добавлен в очередь");}
}
//---------------------------------------------------------------------------
 
void __fastcall TForm1::Button2Click(TObject *Sender)
{
int i=0;
// блокировка потока
DWORD ThID=StrToInt(Edit1->Text);
 
fifo *cur;
cur = first->next;
while (cur!=NULL) {
 
if((cur->tStady!=run)&(cur->tID==ThID)){
  cur->tStady=blok;
  i=cur->tID;
  st="Поток "+IntToStr(i)+" заблокирован";
  }
  cur=cur->next;}
}
//---------------------------------------------------------------------------
 
void __fastcall TForm1::Button3Click(TObject *Sender)
{
int i=0;
// разблокировка потока
DWORD ThID=StrToInt(Edit1->Text);
 
fifo *cur;
cur = first->next;
while (cur!=NULL) {
if((cur->tStady!=run)&(cur->tID==ThID)){
  cur->tStady=wait;
  i=cur->tID;
  st="Поток "+IntToStr(i)+" разблокирован";
  }
  cur=cur->next;}
}
//---------------------------------------------------------------------------
 
void __fastcall TForm1::Button4Click(TObject *Sender)
{
//   завершить поток
int ThreadID=StrToInt(Edit1->Text);
hThread = OpenThread(THREAD_ALL_ACCESS,FALSE, ThreadID);
  if (hThread != NULL){
if (TerminateThread(hThread,0)){
 Memo1->Lines->Add("Поток "+IntToStr(ThreadID)+" завершен!");
 }}
}
//---------------------------------------------------------------------------
 
void __fastcall TForm1::Button5Click(TObject *Sender)
{
DWORD id;
timeKuant=StrToInt(Edit2->Text);
st="Планировщик запущен";
HANDLE h=CreateThread(NULL,0,StartPlan,0,0,&id);
// StartPlan();
}
//---------------------------------------------------------------------------
 
void __fastcall TForm1::Button6Click(TObject *Sender)
{
started=false;
st="Планировщик остановлен";
}
//---------------------------------------------------------------------------
Комментарий преподавателя:
"Создавать потоки не надо, программа должна имитировать работу планировщика, запуская обработчики всех пяти событий по кнопкам или командам меню."

Подскажите, пожалуйста, какие варианты реализации есть, если потоки не создавать? Обработчики итак вроде как на кнопках висят... И как это сделать, если можно.
Ответ:
Сообщение от Olesta
Программная реализация простого бесприоритетного планировщика потоков.
Сообщение от Olesta
завершение кванта времени у активного потока
То есть, "простой" планировщик потоков с вытесняющей многозадачностью. Такая многозадачность требует:
1) Принудительно отобрать управление у потока по таймеру.
2) Сохранить при этом состояние всех регистров процессора.
3) Восстановить состояние регистров того потока, которому передается управление.
Пункты 1 и 2 реализованы аппаратно и вас в эту аппаратную часть никто не пустит.

Короче, передайте преподавателю что он рухнул с дуба.
Вопрос: Не работает поток чтения из COM порта

Программа открывает COM порт и шлет в него 8-ми битное значение. Поток передачи работает: на TX повесил светодиод - вспыхивает, а вот поток передачи молчит. При его выполнении должен появляться MessageBox, но его нет. Т.к. не знаю в чем проблема привожу код и main и com
main:
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
#include <tchar.h>      //для поддержки кодировки Unicode
#include "com.h"
#define ID_BUTTON_1 3000     //идентификатор кнопки
#define ID_BUTTON_2 3001     //идентификатор кнопки
#define ID_BUTTON_3 3002     //идентификатор кнопки
#define ID_BUTTON_4 3003     //идентификатор кнопки
#define ID_COMBOCOM 1003     //идентификатор меню-списка 
 
 
HWND hBtn1;         // хендл  кнопки 1
HWND hBtn2;         // хендл  кнопки 2
HWND hBtn3;         // хендл  кнопки 3
HWND hBtn4;         // хендл  кнопки 4
HWND hComboPort;    // хендл  меню  ComboBox портов
HINSTANCE hInstance;
HBRUSH hbrush;      //создаём объект-кисть
PAINTSTRUCT ps;     //структура рисования
HDC hdc;            //создаём контекст устройства
HDC memdc;          //создаём контекст устройства 
char ComNameBuf[5]; //имя порта (например, "COM1", "COM2" и т.д.)
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
 
 
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
 
    HWND hMainWnd;  // Дескриптор будущего главного окна
    char szClassName[] = "MyClass";
    MSG msg;        // Структура для хранения сообщения
    WNDCLASSEX wc;  // Класс окна
 
    // Заполняем структуру класса окна
    wc.cbSize = sizeof(wc);
    wc.style = CS_HREDRAW | CS_VREDRAW;// Стили класса, в данном случае - окна этого класса будут перерисовываться при изменении размеров по вертикали и горизонтали
    wc.lpfnWndProc = WndProc; // Указатель на функцию, обрабатывающую оконные сообщения
    wc.cbClsExtra = 0;        // Нет дополнительных данных класса 
    wc.cbWndExtra = 0;        // Нет дополнительных данных окна
    wc.hInstance = hInstance; // дескриптор приложения, который регистрирует класс
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); // Стандартная иконка
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);   // Стандартный курсор
    wc.hbrBackground = (HBRUSH)GetStockObject(DKGRAY_BRUSH);// Цвет фона рабочей области окна
    wc.lpszMenuName = NULL;   // Нет меню
    wc.lpszClassName = "MyClass"; // Имя класса окна
    wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
 
    // Регистрируем класс окна
    if (!RegisterClassEx(&wc)) {// Регистрация класса, в случае неудачи фукция вернет 0
        MessageBox(NULL, "Cannot register class", "Error", MB_OK);
        return 0;
    }
 
    // Создаем основное окно приложения
    hMainWnd = CreateWindow(szClassName, "Fluttershy is Present", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, 330, 300, NULL, NULL, hInstance, NULL);
    if (!hMainWnd)
    {
        MessageBox(NULL, "Cannot create main window", "Error", MB_OK);
        return 0;
    }
    
    // Показываем окно
    ShowWindow(hMainWnd, nCmdShow);
    UpdateWindow(hMainWnd);
 
    // Выполняем цикл обработки сообщений до закрытия приложения
    while(GetMessage(&msg, NULL, 0, 0)) 
    {
        TranslateMessage(&msg);// Функция трансляции кодов нажатой клавиши
        DispatchMessage(&msg); // Посылает сообщение функции WndProc()
    }
 
    return msg.wParam;
}
 
LRESULT CALLBACK WndProc(HWND hMainWnd, UINT msg, WPARAM wParam, LPARAM lParam) 
{
  int SelectedCom=1;
  int maxX=0, maxY=0; //максимальные координаты по х и по у
  HBITMAP hbit;       //объект изображение окна
  
    switch (msg) 
    {
        case WM_CREATE:
        {  
          hdc=GetDC(hMainWnd);                //получаем контекст изображения
          maxX=GetSystemMetrics(SM_CXSCREEN); //узнаём максимальные координаты по х  
          maxY=GetSystemMetrics(SM_CYSCREEN); //узнаём максимальные координаты по у
          //Создаем Combobox ;
          hComboPort=CreateWindow("Combobox",NULL,WS_CHILD|WS_VISIBLE|WS_VSCROLL|CBS_DROPDOWNLIST,170, 40, 120, 40,hMainWnd, (HMENU)ID_COMBOCOM,hInstance,NULL);
          //Создаем кнопки ;
          hBtn1 = CreateWindow("BUTTON", "Open COM port", BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD | WS_TABSTOP, 40, 40, 120, 40, hMainWnd, (HMENU)ID_BUTTON_1, hInstance, NULL);
          hBtn2 = CreateWindow("BUTTON", "Close COM port", BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD | WS_TABSTOP, 40, 100, 120, 40, hMainWnd, (HMENU)ID_BUTTON_2, hInstance, NULL);
          hBtn3 = CreateWindow("BUTTON", "Send", BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD | WS_TABSTOP, 40, 160, 120, 40, hMainWnd, (HMENU)ID_BUTTON_3, hInstance, NULL);
          hBtn4 = CreateWindow("BUTTON", "Choose", BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD | WS_TABSTOP, 170, 100, 120, 40, hMainWnd, (HMENU)ID_BUTTON_4, hInstance, NULL);
          //Заносим значения портов:
          SendMessage(hComboPort, CB_ADDSTRING, 1, (LPARAM)"COM1");
          SendMessage(hComboPort, CB_ADDSTRING, 1, (LPARAM)"COM2");
          SendMessage(hComboPort, CB_ADDSTRING, 1, (LPARAM)"COM3");
          SendMessage(hComboPort, CB_ADDSTRING, 1, (LPARAM)"COM4");
          SendMessage(hComboPort, CB_ADDSTRING, 1, (LPARAM)"COM5");
          SendMessage(hComboPort, CB_ADDSTRING, 1, (LPARAM)"COM6");
          SendMessage(hComboPort, CB_ADDSTRING, 1, (LPARAM)"COM7");
          SendMessage(hComboPort, CB_ADDSTRING, 1, (LPARAM)"COM8");
          SendMessage(hComboPort, CB_ADDSTRING, 1, (LPARAM)"COM9");
          SendMessage(hComboPort, CB_SETCURSEL, 0, 0L);  //Делаем текущим первую строчку
          memdc=CreateCompatibleDC(hdc);                 //создём в памяти контекст, совместимый с нашим
          hbit=CreateCompatibleBitmap(hdc, maxX, maxY);  //создаём картинку нашего окна
          SelectObject(memdc, hbit);                     //делаем её активной в области контекста памяти
          hbrush=CreateSolidBrush(RGB(255,255,255));     //создаём кисть
          SelectObject(memdc, hbrush);                   //делаем её активной
          PatBlt(memdc, 0,0,maxX, maxY, PATCOPY);        //копируем картинку из памяти в наше окно, растянув её на всё окно
          ReleaseDC(hMainWnd, hdc);                      //освобождаем контекст
          ComNameBuf[0]=0;  //изначально имя COM порта не выбрано
          
          reader =(HANDLE)_beginthreadex(NULL, 0, ReadThread, pCharRead, 0, NULL); //создаем поток чтения в запущеном состоянии, дескриптор преобразовывается явно в (HANDLE)
          writer =(HANDLE)_beginthreadex(NULL, 0, WriteThread, pCharWrite, CREATE_SUSPENDED, NULL);//создаем поток записи в остановленном состоянии, дескриптор преобразовывается явно в (HANDLE)
          return 0;
        }
        
         case WM_PAINT:
        {
          hdc=BeginPaint(hMainWnd, &ps); 
          //Заголовки над элементами управления
          SetTextColor(hdc, RGB(255,255,67));
          SetBkMode(hdc, TRANSPARENT);
          TextOut(hdc, 170, 70,"Выберите COM порт: ", 17); //выводим текст в окно
          //Перерисовка окна
          memdc=CreateCompatibleDC(hdc);
          BitBlt(hdc, 0, 0, maxX, maxY, memdc, 0, 0, SRCCOPY); //копирует в окно сохранённую картинку 
          EndPaint(hMainWnd, &ps);
          return 0;
        }
        
        case WM_COMMAND:
            switch(LOWORD(wParam))
            {
                case ID_BUTTON_1: //если нажата кнопка открытия порта
                    COMOpen(ComNameBuf);
                    return 0;
                break;
                
                
                case ID_BUTTON_2: //если нажата кнопка закрытия порта
                    COMClose(); 
                    return 0;                   
                break;
 
                
                case ID_BUTTON_3: //если нажата кнопка передачи
                {
                    CharWrite = (char)0b10101010;
                    
                    if(PrtOpen) //если порт открыт
                    { 
                      if(!reader) //если поток чтения не запущен
                      {
                        ResumeThread(reader); //пробуждаем поток чтения
                      }
                      if(!writer) //если поток записи не запущен
                      {
                        ResumeThread(writer); //пробуждаем поток записи
                      }
                      WriteThread(pCharWrite); //передаем в функцию потока записи указатель на передаваюмую переменную(char)
                    }
                    else
                    {
                      MessageBox(NULL, "Порт не открыт", "Error", MB_SYSTEMMODAL);
                    }
                    return 0;
                }
                break;
                
                case ID_BUTTON_4: //если нажата кнопка подтверждения выбора порта
                {
                  SelectedCom=SendMessage(hComboPort, CB_GETCURSEL, 0, 0L);//Получить из списка текст выделенной строки
                  //Сообщение CB_GETLBTEXT (Get ListBox Text) записывает в строку ComNameBuf текст строки с номером SelectedCom. Для этого она даже не должна быть выделена
                  SendMessage(hComboPort, CB_GETLBTEXT, (WPARAM)SelectedCom, (LPARAM)ComNameBuf);
                }
                break;
                
            }  
            break;
            
        case WM_CLOSE:
            COMClose();
            DestroyWindow(hMainWnd);
            return 0;
 
        case WM_DESTROY:
            COMClose();
            PostQuitMessage(0);
            return 0;   
            
        case WM_KEYDOWN:
            switch(wParam) 
            {
                case VK_ESCAPE:                 
                    SendMessage(hMainWnd, WM_CLOSE, 0, 0);
                    break;
            }
            break;
        
        case WM_SIZE: //при изменении размеров окна, взывается 
           InvalidateRect(hMainWnd, NULL, 1); //сообщение WM_PAINT
        break;
        
        default:return DefWindowProc(hMainWnd, msg, wParam, lParam);
    }
    return 0;
}
Ответ: com.cpp
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
#include <windows.h>
#include <stdint.h>     //uint8_t - 8 битный int
#include <process.h>    //для функций _beginthreadex
#include <string>       //для работы со строками
#include <io.h>         //для работы с файлами
#include <fcntl.h>      //для работы с файлами
#include <sys\stat.h>   //для работы с файлами
#include <thread>       //для работы с потоками
//using namespace std;
#define BUFSIZE 255 //размер приемного и передающего буферов
 
HANDLE hSerial;   //дескриптор com порта 
HANDLE reader;    //дескриптор потока чтения
HANDLE writer;    //дескриптор потока записи
int file;         //дескриптор для работы с файлом с помощью библиотеки <io.h>
bool fl=0;        //флаг, указывающий на успешность операций записи (1 - успешно, 0 - не успешно)
bool PrtOpen=0;   //флаг, указывающий на успешность открытия порта (1 - успешно, 0 - не успешно)
unsigned long counter = 0;  //счётчик принятых байтов, обнуляется при каждом открытии порта
char CharRead, CharWrite;   //приёмная и передающая переменные
char *pCharRead = &CharRead, *pCharWrite = &CharWrite;  //указатели на приёмную и передающую переменные
//эти структуры необходимо объявить глобально, иначе программа не будет работать правильно
OVERLAPPED overlappedread;   //будем использовать для операций чтения
OVERLAPPED overlappedwrite;  //будем использовать для операций записи             
unsigned __stdcall ReadThread(void* param);    //функция потока чтения в стиле C++
unsigned __stdcall WriteThread(void* param);   //функция потока записи в стиле C++
DWORD ResumeThread(HANDLE hThread); //функция запуска потока
DWORD SuspendThread(HANDLE hThread);//функция останова потока
void COMOpen(char ComNameBuf[]);    //открыть порт
void COMClose(void);                //закрыть порт
void ReadPrinting(void);
 
LPCTSTR WindowText = "Выберите COM порт: ";
 
//---------------------------------------------------------------------------
 
//функция открытия и инициализации порта
void COMOpen(char ComNameBuf[])
{
 std::string portname;       //имя порта (например, "COM1", "COM2" и т.д.)
 DCB dcb;                //структура для общей инициализации порта DCB
 COMMTIMEOUTS timeouts;  //структура для установки таймаутов
 if (ComNameBuf[0]==0)
 {
    MessageBox(NULL, "Выберите порт", "Error", MB_SYSTEMMODAL);
 }
 else
 {
    portname = ComNameBuf;  //получить имя выбранного порта
 }
 //открыть порт, для асинхронных операций обязательно нужно указать флаг FILE_FLAG_OVERLAPPED
 hSerial = CreateFile(portname.c_str(),GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
 //здесь:
 // - portname.c_str() - имя порта в качестве имени файла, c_str() преобразует строку типа String в строку в виде массива типа char, иначе функция не примет
 // - GENERIC_READ | GENERIC_WRITE - доступ к порту на чтение/записть
 // - 0 - порт не может быть общедоступным (shared)
 // - NULL - дескриптор порта не наследуется, используется дескриптор безопасности по умолчанию
 // - OPEN_EXISTING - порт должен открываться как уже существующий файл
 // - FILE_FLAG_OVERLAPPED - этот флаг указывает на использование асинхронных операций
 // - NULL - указатель на файл шаблона не используется при работе с портами
 
 if(hSerial == INVALID_HANDLE_VALUE)            //если ошибка открытия порта
  {
   MessageBox(NULL, "Не удалось открыть порт", "Error", MB_SYSTEMMODAL);       //вывести сообщение в строке состояния
   return;
  }
 
 //инициализация порта
 
 dcb.DCBlength = sizeof(DCB);   //в первое поле структуры DCB необходимо занести её длину, она будет использоваться функциями настройки порта для контроля корректности структуры
 
 //считать структуру DCB из порта
 if(!GetCommState(hSerial, &dcb))   //если не удалось - закрыть порт и вывести сообщение об ошибке в строке состояния
  {
   COMClose();
   MessageBox(NULL, "Не удалось считать DCB", "Error", MB_SYSTEMMODAL);
   return;
  }
 
 //инициализация структуры DCB
 dcb.BaudRate = 115200;       //задаём скорость передачи 115200 бод
 dcb.fBinary = TRUE;                                    //включаем двоичный режим обмена
 dcb.fOutxCtsFlow = FALSE;                              //выключаем режим слежения за сигналом CTS
 dcb.fOutxDsrFlow = FALSE;                              //выключаем режим слежения за сигналом DSR
 dcb.fDtrControl = DTR_CONTROL_DISABLE;                 //отключаем использование линии DTR
 dcb.fDsrSensitivity = FALSE;                           //отключаем восприимчивость драйвера к состоянию линии DSR
 dcb.fNull = FALSE;                                     //разрешить приём нулевых байтов
 dcb.fRtsControl = RTS_CONTROL_DISABLE;                 //отключаем использование линии RTS
 dcb.fAbortOnError = FALSE;                             //отключаем остановку всех операций чтения/записи при ошибке
 dcb.ByteSize = 8;                                      //задаём 8 бит в байте
 dcb.Parity = 0;                                        //отключаем проверку чётности
 dcb.StopBits = 0;                                      //задаём один стоп-бит
 
 //загрузить структуру DCB в порт
 if(!SetCommState(hSerial, &dcb))   //если не удалось - закрыть порт и вывести сообщение об ошибке в строке состояния
  {
   COMClose();
   MessageBox(NULL, "Не удалось установить DCB", "Error", MB_SYSTEMMODAL);
   return;
  }
 
 //установить таймауты
 timeouts.ReadIntervalTimeout = 0;      //таймаут между двумя символами
 timeouts.ReadTotalTimeoutMultiplier = 0;   //общий таймаут операции чтения
 timeouts.ReadTotalTimeoutConstant = 0;         //константа для общего таймаута операции чтения
 timeouts.WriteTotalTimeoutMultiplier = 0;      //общий таймаут операции записи
 timeouts.WriteTotalTimeoutConstant = 0;        //константа для общего таймаута операции записи
 
 //записать структуру таймаутов в порт
 if(!SetCommTimeouts(hSerial, &timeouts))   //если не удалось - закрыть порт и вывести сообщение об ошибке в строке состояния
  {
   COMClose();
   MessageBox(NULL, "Не удалось установить тайм-ауты", "Error", MB_SYSTEMMODAL);
   return;
  }
 
 //установить размеры очередей приёма и передачи
 SetupComm(hSerial,2000,2000);
 PrtOpen=1;
 //создать или открыть существующий файл для записи принимаемых данных
 file = open("test.txt", O_CREAT | O_APPEND | O_BINARY | O_WRONLY, S_IREAD | S_IWRITE);
 
 if(file==-1)       //если произошла ошибка открытия файла
 {
   MessageBox(NULL, "Ошибка открытия файла", "Error", MB_SYSTEMMODAL);  //вывести сообщение об этом в командной строке
 }
 
 MessageBox(NULL, "Порт открыт", "Notice", MB_SYSTEMMODAL); 
 PurgeComm(hSerial, PURGE_RXCLEAR); //очистить принимающий буфер порта
 PrtOpen=1;             //выставляем флаг в "порт открыт" 
 reader =(HANDLE)_beginthreadex(NULL, 0, ReadThread, pCharRead, CREATE_SUSPENDED, NULL); //создаем поток чтения в остановленном состоянии, дескриптор преобразовывается явно в (HANDLE)
 writer =(HANDLE)_beginthreadex(NULL, 0, WriteThread, pCharWrite, CREATE_SUSPENDED, NULL);//создаем поток записи в остановленном состоянии, дескриптор преобразовывается явно в (HANDLE)
 ResumeThread(reader); //пробуждаем поток чтения
}    
 
//---------------------------------------------------------------------------
 
//функция закрытия порта
void COMClose()
{
//Примечание: так как при прерывании потоков, созданных с помощью функций WinAPI, функцией TerminateThread
//        поток может быть прерван жёстко, в любом месте своего выполнения, то освобождать дескриптор
//        сигнального объекта-события, находящегося в структуре типа OVERLAPPED, связанной с потоком,
//        следует не внутри кода потока, а отдельно, после вызова функции TerminateThread.
//        После чего нужно освободить и сам дескриптор потока.
 
 if(writer)     //если поток записи работает, завершить его; проверка if(writer) обязательна, иначе возникают ошибки
  {TerminateThread(writer,0);
   CloseHandle(overlappedwrite.hEvent); //нужно закрыть объект-событие
   CloseHandle(writer);
  }
 if(reader)        //если поток чтения работает, завершить его; проверка if(reader) обязательна, иначе возникают ошибки
  {TerminateThread(reader,0);
   CloseHandle(overlappedread.hEvent);  //нужно закрыть объект-событие
   CloseHandle(reader);
  }
 
 CloseHandle(hSerial);  //закрыть порт
 hSerial=0;             //обнулить переменную для дескриптора порта
 close(file);           //закрыть файл, в который велась запись принимаемых данных
 file=0;                //обнулить переменную для дескриптора файла
 PrtOpen=0;             //выставляем флаг в "порт закрыт" 
 MessageBox(NULL, "Порт закрыт", "Notice", MB_SYSTEMMODAL);
}
 
//---------------------------------------------------------------------------
 
//главная функция потока, реализует приём байтов из COM-порта
unsigned __stdcall ReadThread(void* param)
{
 COMSTAT comstat;                                               //структура текущего состояния порта, в данной программе используется для определения количества принятых в порт байтов
 DWORD btr, temp, mask, signal;                                 //переменная temp используется в качестве заглушки
 overlappedread.hEvent = CreateEvent(NULL, true, true, NULL);   //создать сигнальный объект-событие для асинхронных операций
 SetCommMask(hSerial, EV_RXCHAR);                               //установить маску на срабатывание по событию приёма байта в порт
 while(1)                                                       //пока поток не будет прерван, выполняем цикл
  {
   WaitCommEvent(hSerial, &mask, &overlappedread);                  //ожидать события приёма байта (это и есть перекрываемая операция)
   signal = WaitForSingleObject(overlappedread.hEvent, INFINITE);   //приостановить поток до прихода байта
   if(signal == WAIT_OBJECT_0)                                      //если событие прихода байта произошло
    {
     if(GetOverlappedResult(hSerial, &overlappedread, &temp, true)) //проверяем, успешно ли завершилась перекрываемая операция WaitCommEvent
      if((mask & EV_RXCHAR)!=0)                                     //если произошло именно событие прихода байта
       {
        ClearCommError(hSerial, &temp, &comstat);           //нужно заполнить структуру COMSTAT
        btr = comstat.cbInQue;                              //и получить из неё количество принятых байтов
        if(btr)                                             //если действительно есть байты для чтения
        {
         ReadFile(hSerial, (TCHAR*)param, btr, &temp, &overlappedread);  //прочитать байты из порта в буфер программы
         counter+=btr;                                                   //увеличиваем счётчик байтов
         ReadPrinting();                                                 //вызываем функцию для вывода данных на экран и в файл
        }
       }
    }
  }
}
 
//---------------------------------------------------------------------------
 
//главная функция потока, выполняет передачу байтов из буфера в COM-порт 
unsigned __stdcall WriteThread(void* param)//param это и есть BufferWrite или CharWrite
{
 if(PrtOpen)    //если COM порт открыт
 {
   DWORD temp, signal;  //temp - переменная-заглушка
   bool CykleEnable = 1;
   overlappedwrite.hEvent = CreateEvent(NULL, true, true, NULL);      //создать событие
   while(CykleEnable) //если CykleEnable заменить на PrtOpen, то передача будет идти непрерывно
   {
     WriteFile(hSerial, (TCHAR*)param, strlen((TCHAR*)param), &temp, &overlappedwrite);  //записать байты в порт (перекрываемая операция!)
     signal = WaitForSingleObject(overlappedwrite.hEvent, INFINITE);      //приостановить поток, пока не завершится перекрываемая операция WriteFile
 
     if((signal == WAIT_OBJECT_0) && (GetOverlappedResult(hSerial, &overlappedwrite, &temp, true))) //если операция завершилась успешно
     {
        //MessageBox(NULL, "Передача прошла успешно", "Notice", MB_SYSTEMMODAL);    //вывести сообщение об этом в строке состояния
        CykleEnable = 0; //завершаем цикл
     }
     else 
     {
       MessageBox(NULL, "Ошибка передачи", "Error", MB_SYSTEMMODAL);//иначе вывести в строке состояния сообщение об ошибке
     }   
     SuspendThread(writer);
   }
 }
 else
 {
   MessageBox(NULL, "Сначала откройте COM порт", "Notice", MB_SYSTEMMODAL);   //вывести сообщение об этом в строке состояния
 }
  
}
 
//---------------------------------------------------------------------------
 
//выводим принятые байты на экран и в файл (если включено)
void ReadPrinting()
{
 write(file, pCharRead, strlen(pCharRead));   //записать в файл данные из приёмного буфера
 memset(pCharRead, 0, sizeof(*pCharRead));          //очистить буфер (чтобы данные не накладывались друг на друга)
}
Правда проявилась еще одра проблема - передача двух байтов вместо одного. Обсуждение этой проблемы здесь
Вопрос: Создать нужное количество потоков программно

Конкретнее, можно ли сократить код, создав цикл или какие либо еще итерации с указанием нужного количества потоков (сейчас их 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
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
//поиск переменных для решения уравнения x^3 + y^3 = z^3 - 1
 
namespace ConsoleApp1
{
    class Program
    {
        static long n; static long k = 0;
        static long[] a;
 
        static void Main(string[] args)
        {
            Thread potok2 = new Thread(func2); // создание отдельного потока
            Thread potok3 = new Thread(func3); // создание отдельного потока
            Thread potok4 = new Thread(func4); // создание отдельного потока
            Thread potok5 = new Thread(func5); // создание отдельного потока
            Thread potok6 = new Thread(func6); // создание отдельного потока
            Thread potok7 = new Thread(func7); // создание отдельного потока
            Thread potok8 = new Thread(func8); // создание отдельного потока
 
            Console.Write("Задайте диапазон расчета переменных, до..., нажмите Enter: ");
            n = Convert.ToInt64(Console.ReadLine());
            a = new long[n + 1];
 
            DateTime dold = DateTime.Now;
 
            for (long i = 1; i <= n; i++)
            {
                a[i] = (long)Math.Pow(i, 3);
            }
            potok2.Start();
            potok3.Start();
            potok4.Start();
            potok5.Start();
            potok6.Start();
            potok7.Start();
            potok8.Start();
 
            //код исполняемый в потоках
            for (long x = 2; x <= (long)Math.Pow(((a[n]) - 1) / 2, 1.0 / 3.0); x=x+8)//на 8 потоков
            {
                for (long y = x; y <= (long)Math.Pow(((a[n]) - 1 - a[x]), 1.0 / 3.0); y++)
                {
                    long z3 = a[x] + a[y] + 1;
                    long z = (long)(Math.Pow(z3, 1.0 / 3.0) + 0.5);
 
                    if (a[z] == z3)
                    {
                        k = ++k;
                        Console.WriteLine(k +"   "+ x +"   "+ y+"   "+z);
                    }
                }
            }
            //код исполняемый в потоках
            potok2.Join(); //ждем выполнения всех потоков
            potok3.Join();
            potok4.Join();
            potok5.Join();
            potok6.Join();
            potok7.Join();
            potok8.Join();
 
            TimeSpan sp = DateTime.Now - dold;
            Console.WriteLine(sp);
            Console.Write("Программа завершена. Нажмите "Enter" для выхода...");
            Console.ReadLine();
        }
 
        static void func2()
        {
            // здесь код, который будет выполняться в отдельном потоке
            for (long x = 3; x <= (long)Math.Pow(((a[n]) - 1) / 2, 1.0 / 3.0); x = x + 8)//на 8 потоков
            {
                for (long y = x; y <= (long)Math.Pow(((a[n]) - 1 - a[x]), 1.0 / 3.0); y++)
                {
                    long z3 = a[x] + a[y] + 1;
                    long z = (long)(Math.Pow(z3, 1.0 / 3.0) + 0.5);
 
                    if (a[z] == z3)
                    {
                        k = ++k;
                        Console.WriteLine(k + "   " + x + "   " + y + "   " + z);
                    }
                }
            }
        }
        static void func3()
        {
            //здесь код, который будет выполняться в отдельном потоке
            for (long x = 4; x <= (long)Math.Pow(((a[n]) - 1) / 2, 1.0 / 3.0); x = x + 8)//на 8 потоков
            {
                for (long y = x; y <= (long)Math.Pow(((a[n]) - 1 - a[x]), 1.0 / 3.0); y++)
                {
                    long z3 = a[x] + a[y] + 1;
                    long z = (long)(Math.Pow(z3, 1.0 / 3.0) + 0.5);
 
                    if (a[z] == z3)
                    {
                        k = ++k;
                        Console.WriteLine(k + "   " + x + "   " + y + "   " + z);
                    }
                }
            }
        }
        static void func4()
        {
            //здесь код, который будет выполняться в отдельном потоке
            for (long x = 5; x <= (long)Math.Pow(((a[n]) - 1) / 2, 1.0 / 3.0); x=x+8)//на 8 потоков
            {
                for (long y = x; y <= (long)Math.Pow(((a[n]) - 1 - a[x]), 1.0 / 3.0); y++)
                {
                    long z3 = a[x] + a[y] + 1;
                    long z = (long)(Math.Pow(z3, 1.0 / 3.0) + 0.5);
 
                    if (a[z] == z3)
                    {
                        k = ++k;
                        Console.WriteLine(k + "   " + x + "   " + y + "   " + z);
                    }
                }
            }
        }
        static void func5()
        {
            //здесь код, который будет выполняться в отдельном потоке
            for (long x = 6; x <= (long)Math.Pow(((a[n]) - 1) / 2, 1.0 / 3.0); x = x + 8)//на 8 потоков
            {
                for (long y = x; y <= (long)Math.Pow(((a[n]) - 1 - a[x]), 1.0 / 3.0); y++)
                {
                    long z3 = a[x] + a[y] + 1;
                    long z = (long)(Math.Pow(z3, 1.0 / 3.0) + 0.5);
 
                    if (a[z] == z3)
                    {
                        k = ++k;
                        Console.WriteLine(k + "   " + x + "   " + y + "   " + z);
                    }
                }
            }
        }
        static void func6()
        {
            //здесь код, который будет выполняться в отдельном потоке
            for (long x = 7; x <= (long)Math.Pow(((a[n]) - 1) / 2, 1.0 / 3.0); x = x + 8)//на 8 потоков
            {
                for (long y = x; y <= (long)Math.Pow(((a[n]) - 1 - a[x]), 1.0 / 3.0); y++)
                {
                    long z3 = a[x] + a[y] + 1;
                    long z = (long)(Math.Pow(z3, 1.0 / 3.0) + 0.5);
 
                    if (a[z] == z3)
                    {
                        k = ++k;
                        Console.WriteLine(k + "   " + x + "   " + y + "   " + z);
                    }
                }
            }
        }
        static void func7()
        {
            //здесь код, который будет выполняться в отдельном потоке
            for (long x = 8; x <= (long)Math.Pow(((a[n]) - 1) / 2, 1.0 / 3.0); x = x + 8)//на 8 потоков
            {
                for (long y = x; y <= (long)Math.Pow(((a[n]) - 1 - a[x]), 1.0 / 3.0); y++)
                {
                    long z3 = a[x] + a[y] + 1;
                    long z = (long)(Math.Pow(z3, 1.0 / 3.0) + 0.5);
 
                    if (a[z] == z3)
                    {
                        k = ++k;
                        Console.WriteLine(k + "   " + x + "   " + y + "   " + z);
                    }
                }
            }
        }
        static void func8()
        {
            //здесь код, который будет выполняться в отдельном потоке
            for (long x = 9; x <= (long)Math.Pow(((a[n]) - 1) / 2, 1.0 / 3.0); x = x + 8)//на 8 потоков
            {
                for (long y = x; y <= (long)Math.Pow(((a[n]) - 1 - a[x]), 1.0 / 3.0); y++)
                {
                    long z3 = a[x] + a[y] + 1;
                    long z = (long)(Math.Pow(z3, 1.0 / 3.0) + 0.5);
 
                    if (a[z] == z3)
                    {
                        k = ++k;
                        Console.WriteLine(k + "   " + x + "   " + y + "   " + z);
                    }
                }
            }
        }
    }
}
Откликнувшимся + в карму!
Ответ:
Кликните здесь для просмотра всего текста
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
//поиск переменных для решения уравнения x^3 + y^3 = z^3 - 1
class Program
{
    static long n; static long k = 0;
    static long[] a;
 
    static void Main(string[] args)
    {
        var threads = new List<Thread>();
 
        for (int i = 2; i <= 8; i++)
        {
            int k = i;
            threads.Add(new Thread(() => func(k)));
        }
 
        Console.Write("Задайте диапазон расчета переменных, до..., нажмите Enter: ");
        n = Convert.ToInt64(Console.ReadLine());
        a = new long[n + 1];
 
        DateTime dold = DateTime.Now;
 
        for (long i = 1; i <= n; i++)
        {
            a[i] = (long)Math.Pow(i, 3);
        }
        
        threads.ForEach(t => t.Start());
 
        //код исполняемый в потоках
        func(2);
        
        //код исполняемый в потоках
        threads.ForEach(t => t.Join()); //ждем выполнения всех потоков
      
        TimeSpan sp = DateTime.Now - dold;
        Console.WriteLine(sp);
        Console.Write("Программа завершена. Нажмите "Enter" для выхода...");
        Console.ReadLine();
    }
 
    static void func(long start)
    {
        // здесь код, который будет выполняться в отдельном потоке
        for (long x = start; x <= (long)Math.Pow(((a[n]) - 1) / 2, 1.0 / 3.0); x = x + 8)//на 8 потоков
        {
            for (long y = x; y <= (long)Math.Pow(((a[n]) - 1 - a[x]), 1.0 / 3.0); y++)
            {
                long z3 = a[x] + a[y] + 1;
                long z = (long)(Math.Pow(z3, 1.0 / 3.0) + 0.5);
 
                if (a[z] == z3)
                {
                    k = ++k;
                    Console.WriteLine(k + "   " + x + "   " + y + "   " + z);
                }
            }
        }
    }
}
Вопрос: Единый блок кода для всех потоков

Как выполнить блок кода для всех потоков 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
using System;
using System.Threading;
using System.Windows.Forms;
 
namespace WindowsFormsApplication17
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        public object obj = new object();
        private void btnStart_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < 3; i++)
            {
                Thread Potok = new Thread(Work);
                Potok.IsBackground = true;
                Potok.Start();
            }
        }
        public void Work()
        {
            while (true)
            {
                if (_png > 0)
                {
                    // Метод Work конвентирует картинки из одного формата в другой.
                }
                else
                {
                    //Блок кода, если в папке закончились картинки.
                    lock (obj) // Чтобы не выскочило 3 MessageBox, но это временное решение, после того как 1 поток продолжит работу, то 2 поток выведет мессадж бокс, а потом и 3-ий. 
                    {
                        MessageBox.Show("Выберите папку с картинками"); // когда нажимает ок, поток выполняет проверку заного и продолжает работу
                        // но надо нажимать 3 раза( 3 потока запускаю ) Как сделать чтобы 1 нажатие на MessageBox означало нажатие и на других.
                    }
                }
            }
        }
 
        private void btnLoadFile_Click(object sender, EventArgs e)
        {
            //происходит подсчет картинок в папке и передает переменной _png кол-во.
        }
    }
}
Ответ:
Сообщение от Derevyniy
Попробую максимально описать свою задачу
Спасибо за подробное объяснение задачи. Но я и с первого раза понял что вам нужно
И решение вашей задачи полностью описано в моем посте.
Я вам предлагал создать еще один поток, который будет следить за состоянием других потоков. И как только все они завершат работу - выдать сообщение пользователю.
Вот подробное решение:
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
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Threading;
using System.Windows.Forms;
 
namespace WindowsFormsApplication330
{
    public partial class Form1 : Form
    {
        private Button btStart;
        private TaskQueue taskQueue;
 
        public Form1()
        {
            InitializeComponent();
 
            btStart = new Button { Text = "Start", Parent = this };
            btStart.Click += bt_Click;
        }
 
        void bt_Click(object sender, EventArgs e)
        {
            //выбираем папку
            var dlg = new FolderBrowserDialog();
            if (dlg.ShowDialog() == DialogResult.OK)
            {
                //блокируем кнопку
                btStart.Enabled = false;
                //запускам поток сканирования директории и поиска картинок
                new Thread(() => FindFiles(dlg.SelectedPath)) { IsBackground = true }.Start();
                //возвращаем управление GUI потоку, что форма не подвисала
                return;
            }
        }
 
        //поток сканирования директории и поиска картинок
        void FindFiles(string path)
        {
            var threads = new List<Thread>();
            taskQueue = new TaskQueue();
 
            //сканируем папку, ищем картинки
            foreach (var file in Directory.EnumerateFiles(path, "*.*", SearchOption.AllDirectories))
                switch (Path.GetExtension(file).ToLower())
                {
                    case ".png":
                    case ".bmp":
                    case ".jpg":
                    case ".jpeg":
                        taskQueue.Enqueue(file);//добавляем в очередь задач
                        break;
                }
 
            //запускаем потоки обработки картинок
            for (int i = 0; i < Environment.ProcessorCount - 1; i++)
            {
                var th = new Thread(ProcessFile) { IsBackground = true };
                th.Start();
                //добавляем поток в список потоков
                threads.Add(th);
            }
 
            //ждем завершения всех потоков
            foreach (var t in threads)
                t.Join();
            //все потоки завершены, вызываем метод в GUI потоке
            Invoke((MethodInvoker)OnCompleted);
        }
 
        //поток обработки файлов
        void ProcessFile()
        {
            var file = "";
            while (taskQueue.TryDequeue(out file))//берем очередной файл из очереди
            {
                try
                {
                    using (var bmp = new Bitmap(file))
                    {
                        //обрабатываем файл ...
                        Thread.Sleep(10);
                        //для отладки выводим в консоль
                        Console.WriteLine("Thread id: {0} Prcessed file: {1}", Thread.CurrentThread.ManagedThreadId, Path.GetFileName(file));
                    }
                }
                catch (Exception ex)
                {
                    //не смогли открыть файл
                    Console.WriteLine("Thread id: {0} Error file: {1}", Thread.CurrentThread.ManagedThreadId, Path.GetFileName(file));
                }
            }
        }
 
        //этот метод будет вызван после окончания процесса обработки файлов
        void OnCompleted()
        {
            //включаем кнопку
            btStart.Enabled = true;
            //сообщаем юзеру об окончании процесса
            MessageBox.Show("Completed");
        }
    }
 
    //очередь заданий
    class TaskQueue : ConcurrentQueue<string>
    {
    }
}
Обратите внимание - создается еще один поток, который сначала сканирует директории, формирует очередь заданий. Затем этот же поток запускает потоки обработки. И затем ждет окончания всех этих потоков. После чего вызывает обработчик окончания процесса OnCompleted в контексте GUI потока.
Метод OnCompleted разблокирует кнопку старта, и выдает сообщение об окончании процесса пользователю.
При этом, сообщение выдается только один раз. Кроме того, пока файлы обрабатываются GUI поток свободен, форма не виснет.
Вопрос: Последовательность выполения потоков

Не знал в какую тему говорить, вещаю сюда

вопчем такой простой код

Java(TM) 2 Platform Standard Edition 5.0
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
class Sync{
    public static void main(String ... args){
        Thread head = Thread.currentThread();
        System.out.println("Главный поток: " + head);
 
        OneThread one = new OneThread(4, "Первый поток");
        OneThread two = new OneThread(3, "Второй поток");
 
        System.out.println("ВЫПОЛНЕНИЕ ГЛАВНОГО ПОТОКА 1");
        try{
            Thread.sleep(1000);
        } catch (InterruptedException e){
            System.out.println("Перехват ошибки главного потока");
        }
        System.out.println("ВЫПОЛНЕНИЕ ГЛАВНОГО ПОТОКА 2");
        System.out.println("ВЫПОЛНЕНИЕ ГЛАВНОГО ПОТОКА 3");
        
        System.out.println("Главный поток завершен");
    }
}
 
class OneThread extends Thread{
    String name;
    int priority;
    OneThread(int howpriority, String howname){
        super("Поток второго уровня");
        priority = howpriority;
        name = howname;
        setPriority(priority);      
        System.out.println("Запущен " + name);
        start();
    }
 
    public void run(){
        System.out.println(name + " выполняется");
    }
}
По моей задумке должен сначала выводится главный поток 1 и потом доп потоки

ВЫПОЛНЕНИЕ ГЛАВНОГО ПОТОКА 1
Первый поток выполняется
Второй поток выполняется
ВЫПОЛНЕНИЕ ГЛАВНОГО ПОТОКА 2
ВЫПОЛНЕНИЕ ГЛАВНОГО ПОТОКА 3
и так действительно происходит в 3 случаях из 4-х...
А иногда получается такой вывод

Первый поток выполняется
ВЫПОЛНЕНИЕ ГЛАВНОГО ПОТОКА 1
Второй поток выполняется
ВЫПОЛНЕНИЕ ГЛАВНОГО ПОТОКА 2
ВЫПОЛНЕНИЕ ГЛАВНОГО ПОТОКА 3
И этого я не пойму, почему главный поток до остановки передает управление на первый поток?
Ответ:
Сообщение от jackie07
И этого я не пойму, почему главный поток до остановки передает управление на первый поток?
Ничего не понятно. Потоки - это такая "абстракция", которая позволяет код выполнять параллельно. Вы всё написали, чтобы код выполнялся параллельно.
Почему вы ожидаете, что второстепенные потоки будут чего-то ждать от главного? Их запустили - они и работают.
Вопрос: Как уничтожить поток?

Delphi
1
2
3
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Threads.MyThreads.Free;//Не канает.
пишит _[dcc32 Error] Unit1.pas(60): E2076 This form of method call only allowed for class methods or constructor

Как можно проверить на то, уничтожен ли поток, (в операторе if) из другого юнита. Пробывал использовать terminate и terminated , Даже в подсказках (Ctrl + Пробел) нету их.
Ответ: Штатное средство для проверки завершения потока (свойство Finished) появилось в Delphi только в версии 2009 (до этого было поле FFinished, но в секции private, без доступа извне).
Поэтому выход для более младший версий – в самом потоке перед завершением установить значение какой-то внешней переменной, например, ThreadIsTerminated := True, а в "главном" потоке (например, в FormClose) проверять её. Либо сесть на OnTerminate и делать это (установку переменной).

Чтобы "завершить" поток, нужно выполнить метод Terminate, а в самом потоке периодически проверять свойство Terminated и завершать работу (выходить из метода Execute), если оно = True. Использовать WinAPI-функцию TerminateThread крайне не рекомендуется (это можем породить утечки памяти и пр.) – она создана на самый крайний случай.

Если при этом нужно дождаться завершения потока, то в "главном" потоке (в FormClose) нужно вызвать WaitFor, а затем Free (в этом случае проверка потоком свойства Terminated с последующим завершением работы критически важна, иначе FormClose попросту зависнет, ожидая завершения потока, если он бесконечен). Хотя, в принципе, можно обойтись и просто методом Free (без Terminate и WaitFor), поскольку в него встроена и установка флага Terminated, и ожидание завершения потока

Если ждать не хочется, тогда добавляем в Execute (можно в начало, можно в конец - неважно) FreeOnTerminate := True, а в FormClose устанавливаем ещё одну переменную-флаг, например, ThreadTerminate := True (вместо вызова Terminate). В Execute же теперь проверяем не Terminated, а ThreadTerminate. Поток в этом случае (при FreeOnTerminate равном) после завершения освободит память сам (вернее, это сделает за него специальная внутренняя функция модуля Classes). Важно: если мы делаем FreeOnTerminate := True, то никакого обращения к объекту (MyThreads) в "главном" потоке быть не должно, т.к. поток может завершиться в любой момент, и MyThreads будет содержать указатель на несуществующий объект потока.

Почему именно так? Почему в FormClose нельзя сделать Terminate? По той же самой причине, что я только что описал: поток может завершиться в любой момент, и MyThreads будет содержать указатель на несуществующий объект потока (а вызвать метод Terminate из несуществующего объекта мы не можем). Даже если мы сделаем так:
Delphi
1
if not ThreadIsTerminated then Terminate;
то может случиться (маловероятно, но может) так, что поток завершится как раз между if not ThreadIsTerminated и Terminate.
Конечно, можно реализовать данный механизм с Terminate + Terminated (вместо использования внешней переменной ThreadTerminate), но для этого либо придётся использовать критические секции (а это лишнее нагромождение), либо метод Execute должен быть бесконечным и завершаться только после вызова Terminate (т.е. при установке свойства Terminated в True).

p.s. Кстати, если мы решим снова запустить потоки, то нам следует дождаться, когда ThreadIsTerminated будет = True, чтобы во-первых, не запустить новый поток параллельно старому (хотя это может быть не страшно – зависит от того, что именно происходит в потоке), а во-вторых, установив ThreadTerminate := False (мы же должны будем это сделать перед запуском новых потоков) мы сделаем так, что старый поток не узнает о том, что ему нужно завершить свою работу и будет работать дальше. Это, конечно, может быть не очень удобно, но альтернатива этому – это либо описанный ранее вариант с ожиданием (см. выше WaitFor), либо использование критических секций и FreeOnTerminate в Execute. Правда, как уже сказано, если метод Execute завершается только при закрытии формы, то можно обойтись и без критических секций . Однако(!), если в программе много мест завершения потока (например, по нажатию кнопки, закрытию формы и т.д.), то вместо простого Terminate надо сделать проверку:
Delphi
1
2
3
4
5
if MyThreads <> nil then
begin
  MyThreads.Terminate;
  MyThreads := nil
end
...надеюсь, понятно почему? На всякий случай скажу: мы уже дали потоку команду завершения (например, нажатием кнопки), и когда попытаемся вызвать Terminate снова (например, при закрытии формы), то можем обратиться к методу Terminate уже несуществующего объекта (у нас же FreeOnTerminate := True). Здесь же можно не париться о том, что поток завершится между if MyThreads <> nil и MyThreads.Terminate, ведь он у нас бесконечный и сам по себе не завершится, если Terminated <> True, а код обработки нажатия кнопки и завершения формы одновременно выполняться тоже не может. Собственно, в данном случае мы можем даже обращаться к методам и свойствам переменной MyThreads, предварительно проверяя её на nil.

p.p.s. Надеюсь, написал понятно и не слишком сильно загрузил
p.p.p.s. Специально выделил выдуманные переменные синим цветом, чтобы не путать их со "встроенными" свойствами.
Вопрос: Нужно контролировать количество запущенных потоков

Предполагается выполнять ресурсоемкие вычисления в 4-х потоках одновременно. Нужно постоянно проверять количество выполняющихся потоков и если их менее 4 то запускаем новый.
Для контроля количества работающих потоков вводим глобальную переменную, не забывая про семафоры, меняем эту переменную при запуске потока и окончании его работы.
Нужно событие об окончании работы потока, чтобы запускать новый поток. Для этого следует использовать делегат или есть другой, более эффективный способ? Как вариант, запустить таймер и сто раз в секунду проверять количество работающих потоков (значение переменной).
Ответ: Можно попробовать так, наверно криво но работать должно
типа переменная для статуса работае-выключен
vb.net
1
2
  Dim WithEvents Mycheck As New CheckBox 'событие для выбора имени поля
    Dim check(4) As CheckBox
типа подготовка переменных и первый запуск потоков
vb.net
1
2
3
4
5
6
7
8
9
10
11
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        For i As Integer = 0 To 3
            check(i) = New CheckBox
            check(i).Name = i
            AddHandler check(i).CheckedChanged, AddressOf Check_CheckedChanged 'привязка обработчика на чекбоксы удаления
        Next
BackgroundWorker0.RunWorkerAsync()
BackgroundWorker1.RunWorkerAsync()
BackgroundWorker2.RunWorkerAsync()
BackgroundWorker3.RunWorkerAsync()
    End Sub
Суть в том что при запуске потока в потоке должно установиться значение check(номер потока).Checked =true
А после завершения check(номер потока).Checked =false
Тогда обработчик при выключении потока определит какой оффнулся и запустит нужный опять
vb.net
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    Private Sub Check_CheckedChanged(sender As Object, e As EventArgs) Handles Mycheck.CheckedChanged
        If sender.Checked = False Then
            Select Case sender.name
                Case "0"
                    BackgroundWorker0.RunWorkerAsync()'запуск нулевого потока
                Case "1"
                   BackgroundWorker1.RunWorkerAsync()'запуск первого потока
                Case "2"
                    BackgroundWorker2.RunWorkerAsync()'запуск второго потока
                Case "3"
                    BackgroundWorker3.RunWorkerAsync() 'запуск третьего потока
            End Select
        Else
        End If
    End Sub
Добавлено через 44 минуты
Вот так поток после завершения будет запускаться повторно, пробовал на одном потоке. Работает бесконечно, нужно допилить условие для завершения.
vb.net
1
2
3
Dim WithEvents Mycheck As New CheckBox 'событие для выбора имени поля
    Dim trd(4) As Thread
    Dim check(4) As CheckBox
vb.net
1
2
3
4
5
6
7
8
9
   Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        For i As Integer = 0 To 3
            check(i) = New CheckBox
            check(i).Name = i
               AddHandler check(i).CheckedChanged, AddressOf Check_CheckedChanged 'привязка обработчика на чекбоксы удаления
        Next i
trd(0) = New Thread(AddressOf trd_strat)
        trd(0).Start()
    End Sub
vb.net
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 Private Sub Check_CheckedChanged(sender As Object, e As EventArgs) Handles Mycheck.CheckedChanged
        If sender.Checked = False Then
            Select Case sender.name
                Case "0"'запуск нулевого потока
                    trd(0).Abort()
                    trd(0) = Nothing
                   
                    trd(0) = New Thread(AddressOf trd_strat)
                    trd(0).Start()
                Case "1"
                   'запуск первого потока
                Case "2"
                   'запуск второго потока
                Case "3"
                    'запуск третьего потока
            End Select
        Else
        End If
    End Sub
vb.net
1
2
3
 Private Sub ch(che As CheckBox, fl As Boolean)
        che.Checked = fl
    End Sub
Сам код потока
vb.net
1
2
3
4
5
6
7
8
    Private Sub trd_strat()
        Invoke(Sub() ch(check(0), True))'флаг что поток запущен
        While 1
            Thread.Sleep(100)
          'тут выполняем что нужно
        End While
        Invoke(Sub() ch(check(0), False))'флаг что поток остановлен
    End Sub