Форум программистов, компьютерный форум, киберфорум
C/C++: WinAPI
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.56/70: Рейтинг темы: голосов - 70, средняя оценка - 4.56
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21281 / 8305 / 637
Регистрация: 30.03.2009
Сообщений: 22,660
Записей в блоге: 30

Вопрос по работе WaitForSingleObject

23.10.2010, 12:01. Показов 15288. Ответов 54
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Постановка задачи следующая. Есть основной процесс, который заведует отображением GUI и есть поток, который делает вычисления. Поток в процессе вычислений периодически должен отдавать результат главному процессу, чтобы тот отобразил результат на GUI. Т.е. схематично процесс работы выглядит так:

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
/* Поток */
...
  for ( ... )
  {
    /* Вычисления */
    ...
 
    /* 1. Записываем результат в глобальную переменную
     * 2. Запираем mutex, чтобы на следующей итерации цикла застрять
     *    на пункте 1, если главный процесс ещё не прочитал результат
     * 3. Посылаем сообщение о готовности результата главному процессу
     * 4. Продолжаем исполнение (переходим к следующей итерации цикла */
  }
...
C
1
2
3
4
5
6
7
8
/* Главный процесс */
 
/* Обработчик, в котором ловим сообщение от потока */
Handler ()
{
  /* 1. Отображаем результат на GUI
   * 2. Освобождаем mutex */
}
В этой схеме для запирания mutex'а (поток, пункт 2) я использовал WaitForSingleObject, а для освобождения mutex'а (главный процесс, пункт 2) - ReleaseMutex. Эта схема не работает.

Я предполагал, что WaitForSingleObject ожидает освобождения mutex'а, а потом запирает его. Предположение росло от того, что пока эту функцию я использовал только в тех случаях, когда mutex запирается и освобождается внутри одного и того же потока. В данном же случае имеем ситуацию, когда mutex запирается в одном потоке, а освобождается в другом. Для подтверждения неправомочности моего предположения достаточно написать исходник, в котором два раза подряд бы запускалось WaitForSingleObject. Если бы моё предположение было верно, то на втором запуске мы бы начали висеть, но этого не происходит.

Вопросы.
1. Просьба пояснить, что конкретно делает WaitForSingleObject. Без ссылок на MSDN и учебники, а своими словами. Чтобы было понятно, почему работает схема, когда mutex запирается и освобождается в одном и том же потоке, но не работает схема, когда это делается в разных потоках
2. Какими интерфейсами правильно осуществить желаемую схему работы
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
23.10.2010, 12:01
Ответы с готовыми решениями:

WaitForSingleObject - вопрос.
Привет. WinApi функция WaitForSingleObject. Как она работает? Ждет завершения патока (тот, что первий параметр), зачем тогда задержка...

Вопрос по работе с таблицей
Такой вот вопрос. Мне нужно поставить условие.. Если группа бюджетная, то итоговая сумма часов записывается в ячейку "Итог по...

Вопрос по работе с файлами
как в строке : open 'имя файла' for input as #1 сделать так чтобы программа искала файл в папке где находится прога повторюсь...

54
306 / 187 / 26
Регистрация: 14.02.2010
Сообщений: 547
24.10.2010, 17:12
Студворк — интернет-сервис помощи студентам
Evg, прямо интересно стало. Может опишите всю задачу и на чем ее рисуете (Pascal / CPP / кака-то экзотика).
0
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21281 / 8305 / 637
Регистрация: 30.03.2009
Сообщений: 22,660
Записей в блоге: 30
24.10.2010, 17:18  [ТС]
Цитата Сообщение от kukuruku310 Посмотреть сообщение
Не понял насчет "нажимать".
Собирательное выражение "куда нажимать" означает что конкретно делать. Ты написал слова "достаточно любой Interlocked-функи и одной переменной". А можно что-нибудь поконкретнее. Название какого-нибудь интерфейса, ссылку на пример или что-нибудь ещё. А то у меня опыт программирования под виндами маленький и таких умных слов я пока не понимаю

Цитата Сообщение от kukuruku310 Посмотреть сообщение
Вы хотите использовать разные места для вычислений разных потоков. А это действительно надо? Может по факту нужен какой-то один результат (последний), и пусть несколько потоков пишут в одно какое-то предопределенное место, доступ к которому идет по, скажем, InterlockedExchange.
Я не хочу описывать свою конкретную задачу, потому что придётся объяснять слишком много ненужных вещей. Я приведу более понятный пример-аналог. Допустим есть несколько устройств, на которые приходят какие-то данные. Программа работает так, что на обработку данных с каждого устройства выделяется один поток. Каждый поток анализирует пришедшие данные и в какой-то момент понимает, что там есть "что-то интересное". Поток должен выдать на GUI'ёвый компонент (например Memo) сообщение типа "на устройстве N5 есть интересные данные 0x10 0x20 0x30" после чего продолжать дальше анализировать входной поток. А основной процесс занимается тем, что принимает от потоков такие сообщения и помещает их в Memo. Точный порядок неважен (т.е. в пределах короткого интервала времени без разницы что в каком порядке напечатано). Важно лишь то, чтобы все данные были отображены. Тормоза при отображении данных некритичны. Т.е. если поток болтался в ожидании, пока главный процесс соизволить принять данные, а в это время на устройство пришло что-то интересное и мы это прощёлкали - не страшно
0
бжни
 Аватар для alex_x_x
2473 / 1684 / 135
Регистрация: 14.05.2009
Сообщений: 7,162
24.10.2010, 17:19
да можно что угодно скрутить, главное понять, что нужно сделать
я не очень понимаю, что требуется
нужно чтобы было несколько потоков читающих (aka читатели), и один поток пишуший (aka писатель)
при этом пока писатель пишет - никто не читает
когда писатель не пишет - читатели могут иметь вперемешку доступ к данным, не ограничивая друг друга ?
0
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21281 / 8305 / 637
Регистрация: 30.03.2009
Сообщений: 22,660
Записей в блоге: 30
24.10.2010, 17:41  [ТС]
Цитата Сообщение от kukuruku310 Посмотреть сообщение
Evg, прямо интересно стало. Может опишите всю задачу и на чем ее рисуете (Pascal / CPP / кака-то экзотика).
Я пока начинающий, а потому ничего сверхсурьёзного. Всего лишь Программа для скачивания биржевых котировок
Но там много всякой своей специфики, а потому чтобы не углубляться в неё, привёл пример-аналог в посте #22

Добавлено через 2 минуты
alex_x_x, ну вот как раз в посте #22 пример-аналог. Дополнительно к вопросу про семафоры могу сказать, что главный процесс временами тоже может смотреть в какое-нибудь устройство и ему нужно будет точно так же выдать данные на печать. Хочется всю печать локализовать в интерфейсе типа PrintData (string), и чтобы вся шайтан-арба была запрятана внутри и не зависела от количества потоков (да и работала бы в варианте, когда вообще потоков нет, а работа с каждым устройством шла бы последовательно и по очереди)

Добавлено через 15 минут
Цитата Сообщение от Evg Посмотреть сообщение
alex_x_x, если дёргать интерфейс из нескольких потоков одновременно, то такая схема хорошо работает и видно, что данные обрабатываются вперемешку из всех потоков. Однако теперь если я попытаюсь воспользоваться этим интерфейсом из главного процесса (например, его тоже задействовать под вычисления), то получится так, что в тот момент, пока идут данные от главного процесса, данные от потока притормаживаются и только по окончании данных от главного процесса начинаются вперемешку считываться данные от потоков. У меня уже фантазию заклинивает по поводу этой наносистемы, но оно так и должно быть (при описанной реализации через два семафора) или нет? В принципе, на текущий момент такой вариант меня устраивает, но хотелось бы понимать, чего ожидать в будующем
Данный вопрос снимаю. Ибо я тормоз

Добавлено через 1 минуту
Локальный итог. Поставленная задача была разрешена при помощи двух семафоров. Но какое-то внутреннее чутьё мне подсказывает, что можно было бы обойтись и одним объектом синхронизации. Т.е. дальнейший разбор полётов уже скорее ради научного интереса
0
306 / 187 / 26
Регистрация: 14.02.2010
Сообщений: 547
24.10.2010, 23:41
Не знаю, криво, все, конечно, и наспех, но вот для консольной версии как я вижу читать/писать многими потоками в общую переменную. Сначала рисовал Interlocked, но, пожалуй что использование мьютекса надежнее.

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
#include <windows.h>
#include <process.h>
#include <conio.h>
#include <tchar.h>
#include <stdio.h>
 
void LastSysError(const char *Caption)
{
    char *ErrBuf = NULL;
    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
                              NULL, GetLastError(), 0, ErrBuf, 0, NULL);                  
    MessageBox(GetActiveWindow(), ErrBuf, Caption, MB_ICONERROR);
    LocalFree(HLOCAL(ErrBuf));
}
 
unsigned int __stdcall CalcThreadProc(void *threadNumber); // поток, следящий за нажатием клавиш - просто для остановки
unsigned int __stdcall KeyboardThreadProc(void *dummy);    // вычислитель
 
bool repeat = true; // работаем, пока true
 
#define getRnd(from, to) ((rand() % (int)(((to) + 1) - (from))) + (from)) // имитация слсучайных данных
 
#define MAX_CALC_THREAD   10                    // число вычисляющих потоков
 
#define GLOBAL_BUFFER_SZ 512       
char globalBuffer[GLOBAL_BUFFER_SZ];    // общий для всех потоков буфер  
DWORD globalBufferBI;                                   // и его текущий индекс
 
int CallCounts[MAX_CALC_THREAD];      // еще одна переменная, но по индексам разделена на потоки 
 
HANDLE hMutex;                        // синхронизация
#define MUTEX_NAME "myMutex"
#define MAX_TIME 5000                 // сколько времени ждать максимум
 
int _tmain(int argc, _TCHAR* argv[])
{
    DWORD retCode;
    
    hMutex = CreateMutex(NULL, FALSE, MUTEX_NAME);
    if (hMutex == NULL)
    {
        LastSysError("CreateMutex");
        return 0;
    }
    
    // запускаем потоки
    _beginthreadex(NULL, 0, KeyboardThreadProc, NULL, 0, NULL);
    DWORD threadCount = 0;
    for (DWORD threadCount = 1; threadCount <= MAX_CALC_THREAD; threadCount++)
    {
        CallCounts[threadCount-1] = 0;
        _beginthreadex(NULL, 0, CalcThreadProc, (void*)(_w64)threadCount, 0, NULL);
    }
    
    // работаем, пока не получим сигнал выхода
    while (repeat)
    {
        // Sleep(500); // но это увеличит риск "нехватки буфера"
        retCode = WaitForSingleObject(hMutex, MAX_TIME);
        switch (retCode)
        {
            case WAIT_OBJECT_0:
            {
                HANDLE newH = OpenMutex(MUTEX_ALL_ACCESS, FALSE, MUTEX_NAME);
                if (NULL != newH) 
                {
                    if (globalBufferBI > 0)
                    {
                        printf("%s", globalBuffer);
                        globalBufferBI = 0;
                    }
                    ReleaseMutex(newH);
                }
                ReleaseMutex(hMutex);
                break;
            }
            case WAIT_TIMEOUT:
            {
                printf("times end\n");
                repeat = false;
                break;
            }
            default:
            {
                printf("\nwait main\n");
                continue;
            }
        }
    }
    ReleaseMutex(hMutex);
    CloseHandle(hMutex);
    return 0;
}
 
unsigned int __stdcall KeyboardThreadProc(void *dummy)
{
    _getch();
    repeat = false;
    return repeat;
}
 
unsigned int __stdcall CalcThreadProc(void *threadNumber)
{
    while(repeat)
    {
        Sleep(500); // для "визуализации"
        int tmp = getRnd(0, 0x1000);
        if ((tmp & (DWORD)(_w64)threadNumber) == (DWORD)(_w64)threadNumber)
        {
            DWORD retCode   = WaitForSingleObject(hMutex, MAX_TIME);
            switch (retCode)
            {
                case WAIT_OBJECT_0:
                {
                    HANDLE newH = OpenMutex(MUTEX_ALL_ACCESS, FALSE, MUTEX_NAME);
                    if (NULL != newH) 
                    {
                        if (globalBufferBI < GLOBAL_BUFFER_SZ - 25)
                        {
                            globalBufferBI += _snprintf(globalBuffer + globalBufferBI, GLOBAL_BUFFER_SZ - globalBufferBI,
                                                                                "%02X %03X %04X\n", 
                                                                                (DWORD)(_w64)threadNumber,
                                                                                ++CallCounts [(DWORD)(_w64)threadNumber-1],
                                                                                tmp);
                        }
                        ReleaseMutex(newH);
                    }
                    else
                        printf("buffer small\n");
                
                    ReleaseMutex(hMutex);
                    break;
                }
                case WAIT_TIMEOUT:
                {
                    printf("times end\n");
                    repeat = false;
                    break;
                }
                default:
                    printf("\n%d=wait\n", (DWORD)(_w64)threadNumber);
            }
        }
    }
    _endthread();
    return 0;
}
Добавлено через 11 минут
Дико извиняюсь, но _endthread() надо, конечно заменить на _endthreadex()
Идиотство - это уже диагноз...

Добавлено через 2 часа 2 минуты
Мля! А ведь работает-то крайне неустойчиво...
0
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21281 / 8305 / 637
Регистрация: 30.03.2009
Сообщений: 22,660
Записей в блоге: 30
24.10.2010, 23:47  [ТС]
Если честно - я нифига не понял, что там делается...
0
306 / 187 / 26
Регистрация: 14.02.2010
Сообщений: 547
25.10.2010, 00:32
Цитата Сообщение от Evg Посмотреть сообщение
Если честно - я нифига не понял, что там делается..
Да и сам уже в полных непонятках... Стоит убрать Sleep-ы - и все летит в тартарары

вот еще вариант, может поможет,
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
// должно быть с опцией линкера /MT (release) или /MTd (debug)
#include <windows.h>
#include <winbase.h>
#include <process.h>
#include <conio.h>
#include <tchar.h>
#include <stdio.h>
 
void LastSysError(const char *Caption)
{
  char *ErrBuf = NULL;
  FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
                NULL, GetLastError(), 0, ErrBuf, 0, NULL);                
  MessageBox(GetActiveWindow(), ErrBuf, Caption, MB_ICONERROR);
  LocalFree(HLOCAL(ErrBuf));
}
 
unsigned int __stdcall CalcThreadProc(void *threadNumber); // поток, следящий за нажатием клавиш - просто для остановки
unsigned int __stdcall KeyboardThreadProc(void *dummy);    // вычислитель
 
bool repeat = true; // работаем, пока true
 
#define getRnd(from, to) ((rand() % (int)(((to) + 1) - (from))) + (from)) // имитация слсучайных данных
 
#define MAX_CALC_THREAD   10          // число вычисляющих потоков
 
#define GLOBAL_BUFFER_SZ 512       
char globalBuffer[GLOBAL_BUFFER_SZ];  // общий для всех потоков буфер  
DWORD globalBufferBI;                  // и его текущий индекс
 
int CallCounts[MAX_CALC_THREAD];      // еще одна переменная, но по индексам разделена на потоки 
                                      // в ней мы будем считать число вызовов для каждого потока
                                      
HANDLE hMutex;                        // синхронизация
#define MUTEX_NAME "myMutex"
#define MAX_TIME 5000                 // сколько времени ждать максимум
 
FILE *log;
 
LONG InUse = FALSE;
 
int _tmain(int argc, _TCHAR* argv[])
{
  log = fopen("fprintf.out", "w");
  globalBufferBI = 0;
  
  hMutex = CreateMutex(NULL, FALSE, MUTEX_NAME);
  if (hMutex == NULL)
  {
    LastSysError("CreateMutex");
    return -1;
  }
  
  // запускаем потоки
  InUse = TRUE; // блокируем на время запуска потоков
  
  _beginthreadex(NULL, 0, KeyboardThreadProc, NULL, 0, NULL);
  DWORD threadCount = 0;
  for (DWORD threadCount = 1; threadCount <= MAX_CALC_THREAD; threadCount++)
  {
    CallCounts[threadCount-1] = 0;
    _beginthreadex(NULL, 0, CalcThreadProc, (void*)(_w64)threadCount, 0, NULL);
  }
  InterlockedExchange((LONG*)&InUse, FALSE); // освобождаем доступ
  
  while (repeat) // работаем, пока не получим сигнал выхода
  {
    while (InterlockedExchange(&InUse, TRUE) == TRUE) // получаем ресурс в свое распоряжение
      Sleep(0);
    
    if (globalBufferBI > 0) // если есть данные для вывода
    {
      printf("%s", globalBuffer);
      fprintf(log, globalBuffer);
      globalBufferBI = 0;
    }
    InterlockedExchange(&InUse, FALSE); // доступ к ресурсу больше не нужен
  }
  
  fclose(log);
  return 0;
}
 
// просто выход по нажатию любой клавиши
unsigned int __stdcall KeyboardThreadProc(void *dummy)
{
  _getch();
  repeat = false;
  return repeat;
}
 
unsigned int __stdcall CalcThreadProc(void *threadNumber)
{
  while(repeat)
  {
    Sleep(1); // без хотя бы какого-то минимального засыпания потоки все равно перемешиваются 
              // хотя, может быть перемешивание идет уже при выводе в файл/на экран, но от этого не легче 
    
    int tmp = getRnd(0, 0x1000); // делаем "случайные данные"
    if ((tmp & (DWORD)(_w64)threadNumber) == (DWORD)(_w64)threadNumber) // если это нужные данные
    {
      while (InterlockedExchange(&InUse, TRUE) == TRUE) // получаем ресурс в свое распоряжение
        Sleep(0);
      if (globalBufferBI < GLOBAL_BUFFER_SZ)
      {
        globalBufferBI += _snprintf(globalBuffer + globalBufferBI, GLOBAL_BUFFER_SZ - globalBufferBI,
                          "%02X %03X %04X\n", 
                          (DWORD)(_w64)threadNumber,
                          ++CallCounts [(DWORD)(_w64)threadNumber-1],
                          tmp);
      }
      InterlockedExchange(&InUse, FALSE); // доступ к ресурсу больше не нужен
    }
  }
  
  _endthreadex(0);
  return 0;
}
краткое пояснение: с помощью InUse разрешаем доступ только кому-то одному к буферу и всему, что с ним связано. InUse нельзя менять напрямую, т.к. это операция не атомарная, поэтому исползуем Interlocked, которая обеспечивает, что к этому значению никто не обратится во время ее изменения.

Но стоит убрать Sleep в начале функции потока - и пошла мешанина в буфере. Данный факт объяснить никак и ничем не могу.

На сегодня это финал.
0
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21281 / 8305 / 637
Регистрация: 30.03.2009
Сообщений: 22,660
Записей в блоге: 30
25.10.2010, 14:46  [ТС]
C
1
2
while (InterlockedExchange(&InUse, TRUE) == TRUE) // получаем ресурс в свое распоряжение
   Sleep(0);
Мягко говоря, это лажа.

Вот пример на linux'е:

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
#include <pthread.h>
 
pthread_mutex_t mutex;
 
int main (void)
{
  fprintf (stderr, "point1\n");
  pthread_mutex_lock (&mutex);
  fprintf (stderr, "point2\n");
  pthread_mutex_lock (&mutex);
  fprintf (stderr, "point3\n");
  return 0;
}
Code
1
2
3
4
5
$ gcc t.c -lpthread
$ ./a.out
point1
point2 <--- тут висим на втором вызове pthread_mutex_lock, потому как mutex уже заблокирован
^C
Неужто нельзя что-то написать под виндами, где вместо pthread_mutex_lock был бы другой интерфейс? Уж сколько раз я под linux'ом матерился на предмет того, что всё через ж...у сделано. Неужто под виндой ещё хуже?
0
306 / 187 / 26
Регистрация: 14.02.2010
Сообщений: 547
25.10.2010, 17:26
Цитата Сообщение от Evg Посмотреть сообщение
Мягко говоря, это лажа
Вполне возможно... как оказалось, хотя она должна (по идее) крутиться в цикле, пока не удасться получить нужное значение. Хотя, я кажется, перепутал-вместо == TRUE надо было наоборот. Но не в этом суть. И так, и этак без Sleep выдает бяку - у меня в комменте там об этом добавлено.
Короче, набросал вот сегодня еще пару вариантов, может глянете. На мой непросвещенный взгляд лучше уж CPU пусть впустую крутит Interlocked какое-там время, чем заставлять его ерзать между User/Kernel.
Хотя, в общем случае, основная проблема не в доступе к общему ресурсу - для этого достаточно одной-единственной критической секции, а в разруливании ситуации нехватки места в общем буфере. И опять все вернулось к динамическому распределению памяти... Хотя... Если применить какой-нить хитрый распределитель, может оно и не так страшно получится? Скажем, много писателей рисуют свои даные ну хотя бы в очередь. Один анализатор эти данные обрабатывает, помечая нужные/ненужные. А один читатель после берет эти данные и удаляет их из очереди.
ну и в качестве PS: я, конечно, ну очень далеко не эксперт в области многопоточности, и, наверное, поэтому всеми правдами-неправдами, стараюсь ее избежать. (И зачастую это получается.) Применяю только в качестве какой-нить сугубо вспомогательной/отладочной фичи. А в основу работы - ни-ни...
Вложения
Тип файла: rar Test.rar (3.4 Кб, 14 просмотров)
0
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21281 / 8305 / 637
Регистрация: 30.03.2009
Сообщений: 22,660
Записей в блоге: 30
25.10.2010, 17:38  [ТС]
kukuruku310, твой архив под линухом что-то не открывается. Попробую дома под виндой. Но я подозреваю, что там очередной наноконцепт В то время, как в примере из поста #13 всё чётко понятно и работает (правда я не понимаю почему, потому что до сих пор не понял, что делает WaitForSingleObject)

По поводу потоков - в моей программе нужно одновременно качать данные с нескольких сайтов. Я не вижу среди простых реализаций что-либо вменяемое, кроме как делать загрузки из инета в отдельных потоках, потому как если загрузки делать в главном потоке, то программа будет постоянно "подвисать" из-за тормозов в сети. А перекладывать на пользователя проблеммы программиста - это неправильно

Добавлено через 1 минуту
Цитата Сообщение от kukuruku310 Посмотреть сообщение
На мой непросвещенный взгляд лучше уж CPU пусть впустую крутит Interlocked какое-там время, чем заставлять его ерзать между User/Kernel
Впустую крутиться в цикле программа будет до тех пор, пока не произойдёт переключение задачи на другой поток, где будет освобождён ресурс, после чего должно произойти переключение задач в обратную сторону и только после этого мы сможем выйти из цикла. Т.е. от переключениё User/Kernel при синхронизации ты никогда и никуда не денешься. Если я правильно понимаю, что делает Interlock
0
306 / 187 / 26
Регистрация: 14.02.2010
Сообщений: 547
25.10.2010, 17:57
странно, паковал как всегда.
насчет наноконцепта-вполне возможно, просто пытаюсь подкинуть идею... Но не согласен по поводу переключения User/Kernel. Критические секции и Interlocked-функции выполняются без выхода из User-mode, поэтому и (в примере 2) старался ими обойтись.
А по поводу WaitForSingleObject - как я понял - ждет освобождения какого-то объекта, если дождалась за отведеное время - возвращает 0, блокирую при этом перед своим выходом этот объект, или taim-out, или еще-что-то, если этот объект был кем-то некорректно освобожден. так я понял Рихтера и MSDN. А уж что там на самом деле внутри....
И еще добавлю - если освобождающий буфер поток (читатель) работает менее/или равно приоритетно, чем куча писателей (как и должно быть), то без динамики выделения памяти все равно не обойтись.
И еще идея: куча писателей могут писать данные не в память, а во временные файлы в каком-то определенном каталоге. А все остальные их оттуда забирают. Если прийти к соглашению о какой-то минимально/максимальной порции данных в файле, то вполне реально обойтись без всяких потоков. А запись/чтение с локального диска все равно будет быстрее любого самого скоростного интернета.
Вложения
Тип файла: zip Up.zip (5.5 Кб, 12 просмотров)
0
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21281 / 8305 / 637
Регистрация: 30.03.2009
Сообщений: 22,660
Записей в блоге: 30
25.10.2010, 18:10  [ТС]
> то вполне реально обойтись без всяких потоков

Как? Работать ручками через TCP-сокет с таймаутом по 0.01 сек (потому что в противном случае программа будет висеть в процессе чтения данных из сокета)?
0
306 / 187 / 26
Регистрация: 14.02.2010
Сообщений: 547
25.10.2010, 18:16
Цитата Сообщение от Evg Посмотреть сообщение
то вполне реально обойтись без всяких потоков
Млин! Ну конечно не о самих потоках речь, а об их синхронизации.
0
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21281 / 8305 / 637
Регистрация: 30.03.2009
Сообщений: 22,660
Записей в блоге: 30
25.10.2010, 18:31  [ТС]
kukuruku310, тебе не кажется, что твои идеи больше смахивают на пляски с бубном, чем на надёжное и простое решение поставленной задачи?
0
306 / 187 / 26
Регистрация: 14.02.2010
Сообщений: 547
25.10.2010, 18:37
Цитата Сообщение от Evg Посмотреть сообщение
kukuruku310, тебе не кажется, что твои идеи больше смахивают на пляски с бубном, чем на надёжное и простое решение поставленной задачи?
Да вообще все это долбление по клавишам - сплошные пляски, и не только с бубном. А надежного, простого + эффективного решения просто напросто может и не существовать. Приходится выбирать лучшее из худшего. Решать Вам.
0
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21281 / 8305 / 637
Регистрация: 30.03.2009
Сообщений: 22,660
Записей в блоге: 30
25.10.2010, 18:59  [ТС]
Цитата Сообщение от kukuruku310 Посмотреть сообщение
Да вообще все это долбление по клавишам - сплошные пляски, и не только с бубном. А надежного, простого + эффективного решения просто напросто может и не существовать. Приходится выбирать лучшее из худшего. Решать Вам.
В очередной раз могу написать, что в посте #13 предоставлено надёжное, простое и эффективное решение. И как бы выбирать лучшее из худшего незачем. Если бы это решение мне не показали, я бы пошёл читать книгу. Правда тут встал бы вопрос о том, что надо просмотреть много книг, потому как далеко не везде адекватно и понятно всё написано. Мне, например, понятно, как работает синхронизация в принципе, но непонятно, как она конкретноработает под виндами. Потому что пока так и не встретил внятного описания того же самого WaitForSingleObject
0
306 / 187 / 26
Регистрация: 14.02.2010
Сообщений: 547
25.10.2010, 19:09
Evg, я еще раз говорю, что выбор за Вами, но попробуйте реализовать (и прогнать во всевозможных режимах) то, что написано в №12, с учетом того, чтобы читатель никогда не терял данные, чтобы читатель никогда не блокировал ни одного писателя и при этом использовался фиксированный буфер ограниченного размера. Для всего, что написано в #12, вполне достаточно одной критич.секции, которая не даст обратиться к буферу одновременно двум потокам.

Все, я выхожу из темы, все равно других идей у меня нет.
0
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21281 / 8305 / 637
Регистрация: 30.03.2009
Сообщений: 22,660
Записей в блоге: 30
25.10.2010, 20:24  [ТС]
Цитата Сообщение от kukuruku310 Посмотреть сообщение
но попробуйте реализовать
Попробовал. Работает.

Цитата Сообщение от kukuruku310 Посмотреть сообщение
Для всего, что написано в #12, вполне достаточно одной критич.секции
В очередной раз хочется вспомнить выражения "куда нажимать?", "мужик, кончай выпендриваться, покажи пальцем в какую сторону плыть" и т.п.
0
306 / 187 / 26
Регистрация: 14.02.2010
Сообщений: 547
25.10.2010, 22:28
Цитата Сообщение от Evg Посмотреть сообщение
Попробовал. Работает
Естественно работает, т.к. по сути логика такая: какой-то поток прочитал данные, разрешил работу только основному, и пока основной не сработает, ни один из потоков-писателей не может работать.
И какая тут многопоточность? Зачем вообще заводить основной поток, если всю работу с тем же успехом сделают сами писатели, помещая результат не в буфер, а посылая его напрямую куда надо. Долго выводить результат? Так ожидание от системы разрешения работать и потом вывод - еще дольше. Зачем там семафор, а тем более 2 - непонятно. Вполне достаточно единственной и куда более легковесной критич.секции.

Ну а по поводу "тыканья пальцем" - так в последнем вложении пример 2 как раз и использует критическую секцию, а потоки блокируются только если буфер переполняется оттого, что выводящий не успевает его освобождать.

Ну хорошо, следуя примеру то ли 12, то ли 13, примерно так:

создание - InitializeCriticalSectionAndSpinCount

захват - EnterCriticalSection
освобождение - LeaveCriticalSection
удаление – DeleteCriticalSection

итого
main
InitializeCriticalSectionAndSpinCount
работа
DeleteCriticalSection

поток и главный поток
EnterCriticalSection
...
LeaveCriticalSection

проверял

в отличие от 12/13 все потоки имеют равные права.

Но основная проблема не в этом - об этом я уже сказал.
0
бжни
 Аватар для alex_x_x
2473 / 1684 / 135
Регистрация: 14.05.2009
Сообщений: 7,162
25.10.2010, 23:08
kukuruku310, критическая секция не учитывает, что можно читать, когда ничего не записано, а так да
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
25.10.2010, 23:08

Вопрос по работе со списками
foreach (var cache in cachelist) { if (cache.datetime &lt; DateTime.Now.AddMinutes(-1)) { ...

Вопрос по работе со списками
&lt;P class=MsoNormal style=&quot;MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: justify &lt;FONT size=3&gt;&lt;FONT color=#000000&gt;&lt;FONT face=&quot;Times New Roman Всем...

Вопрос по работе с TTimer
Прога работает примерно следующим образом. Раз в 5 секунд надо скачать инфу с web'а и обновить таблицу. Работаю через TTimer. Вроде бы всё...

Вопрос о работе с консолью
Здравствуйте. Мне нужно вводить начальные данные в консоль: количество + enter + через пробел цифры. Но проблема в том, что если я упущу...

Вопрос по лабораторной работе
program lab2; var x: array of real; k, n, i: integer; xx, eps, t: real; L: array of real; ff: text; begin assign (ff,...


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

Или воспользуйтесь поиском по форуму:
40
Ответ Создать тему
Новые блоги и статьи
Сам себя обучал rest api
anaschu 02.07.2026
Педагогический лайфхак: Почему чистый REST API для ученика намного круче, чем готовые библиотеки Когда мы отказались от капризного JAR-файла AnyLogic и переписали код на стандартный HttpClient,. . .
rest api anylogic - выполнение модели на своём русском сайте
anaschu 02.07.2026
Как подружиться с AnyLogic Cloud API, победить провайдеров и развернуться Java-бэкенд в Docker на бесплатном хостинге: Двухдневный лог борьбы Всем привет! Хочу поделиться свежим (и довольно. . .
Где деньги лежат
kumehtar 02.07.2026
Это - японская подводная лодка I-52 (тип C2, кодовое имя Momi) вышла из Японии в марте 1944 года с миссией в оккупированную немцами Францию (Лорьян). Это была одна из «Янаги»-миссий по обмену. . .
Krabik для WoW 3.3.5a, многоязычный
AmbA 02.07.2026
Допилил бота, думаю что окончательно. Изменения: - добавлена многоязычность - добавлено снятие скриншотов - добавлено поддержание бафов хождения по воде (для жреца, дк и шамана) - и так, по. . .
Алиса нашла кучу ошибок компиляции и запуска в проекте, который без проблем компилировался и запускался)))
anaschu 30.06.2026
Я пока посмеюся, но завтра проверю. А вообще интерсно. Дал алисе файл, в котором точно нет ошибок компиляции и запуска, и попросил их найти. Нашла кучу))) Критические ошибки, мешающие компиляции и. . .
сукцессия 16. Общий обзор, в основном что бы другие ии поняли
anaschu 29.06.2026
# Передаточный документ: модель микоризной сукцессии (для нового чата) Этот документ предназначен для того, чтобы новый чат Claude мог продолжить работу без необходимости заново разбираться в. . .
сукцессия 15 неявная схема
anaschu 29.06.2026
Алиса Калибровка параметров симбиотической модели: технический обзор Содержание: Введение Постановка проблемы Технические аспекты реализации Процесс внедрения изменений
сукцессия 14. Обновленная схема модели
anaschu 28.06.2026
ГЛОБАЛЬНАЯ ОПИСАТЕЛЬНАЯ СПЕЦИФИКАЦИЯ ЭКОСИСТЕМНОЙ МОДЕЛИ «SOIL CHEMISTRY & MYCORRHIZA 2. 0» https:/ / ibb. co/ NnkGpfMd Представленная интегрированная схема описывает непрерывную нелинейную. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru