С Новым годом! Форум программистов, компьютерный форум, киберфорум
C/C++: WinAPI
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.63/8: Рейтинг темы: голосов - 8, средняя оценка - 4.63
8 / 8 / 5
Регистрация: 28.10.2012
Сообщений: 135

Многопоточность, не правильная работа с мютекосом. Что не так?

02.09.2017, 18:14. Показов 1574. Ответов 17
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Добрый. Хочу чтобы разрешение (permission) устанавливалось только один раз каким-либо потоком, а затем забиралось каким-либо другим.

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
#include <Window.h>
#include <stdlib.h>
#include <time.h> //srand
#include <iostream>
#include <conio.h>
 
#define THREADS1_NUMBER 5
#define THREADS2_NUMBER 5 
 
DWORD WINAPI SetPermission(LPVOID lparam);
DWORD WINAPI GetPermission(LPVOID lparam);
VOID WINAPI UsePermission(LPVOID lparam);
 
bool permission;
HANDLE prmsMuttex; //permission mutex
 
int main(int argc, char* argv[])
{
    srand((unsigned)time(NULL));
 
    HANDLE treads1[THREADS1_NUMBER];
    HANDLE treads2[THREADS1_NUMBER];
 
    prmsMuttex = CreateMutex(NULL, TRUE, NULL);
 
    for (int i = 0; i < THREADS1_NUMBER; i++)
    {
        treads1[i] = CreateThread(NULL, 0, &SetPermission, &prmsMuttex, 0, NULL);
    }
 
    for (int i = 0; i < THREADS2_NUMBER; i++)
    {
        treads2[i] = CreateThread(NULL, 0, &GetPermission, &prmsMuttex, 0, NULL);
    }
 
    _getch();
    
    for (int i = 0; i < THREADS1_NUMBER; i++) 
    {
        CloseHandle(treads1[i]);
    }
    
    for (int i = 0; i < THREADS2_NUMBER; i++)
    {
        CloseHandle(treads2[i]);
    }
    
    CloseHandle(prmsMuttex);
 
    return 0;
}
 
DWORD WINAPI SetPermission(LPVOID lparam)
{
    CONST HANDLE mutex = (CONST HANDLE)lparam;
    
    while (true)
    {
        Sleep(rand());
        
        if (permission)
            continue;
 
        WaitForSingleObject(mutex, INFINITY);
        
        DWORD id = GetCurrentThreadId();
        cout << "thread " << id << " set permission\n";
        permission = TRUE;
        
        ReleaseMutex(&prmsMuttex);  
    }
 
}
 
DWORD WINAPI GetPermission(LPVOID lparam)
{
    CONST HANDLE mutex = (CONST HANDLE)lparam;
    
    while (true)
    {
        Sleep(rand());
 
        if (!permission) 
            continue;
 
        WaitForSingleObject(mutex, INFINITY);
        
        DWORD id = GetCurrentThreadId();                
        cout << "thread " << id << " get permission\n";
        permission = FALSE;
 
        ReleaseMutex(&prmsMuttex);
 
        UsePermission(NULL);            
    }
 
}
 
VOID WINAPI UsePermission(LPVOID lparam)
{
    cout << "call use_permission\n";
}
В чем моя ошибка? Что не так.Спасибо
Миниатюры
Многопоточность, не правильная работа с мютекосом. Что не так?  
0
Лучшие ответы (1)
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
02.09.2017, 18:14
Ответы с готовыми решениями:

Не правильная блок-схема что не так?
программный код выглядит так: procedure TForm1.Button1Click(Sender: TObject); var a:array of real; p:real; i:integer; ...

Работа с капчей. Что не так?
Сделал капчу при добавлении комментариев и не могу соединить это все в 1. Если капча введена правильно - отсылаем комментарий, иначе - не...

Работа с Timer-ом, что не так?
Привет всем! Народ гляньте пожалуйста, кто шарить, что не так с кодом не работает Timer. Что делал:На форме две панели кнопка и Timer. В...

17
807 / 534 / 158
Регистрация: 27.01.2015
Сообщений: 3,017
Записей в блоге: 1
02.09.2017, 18:32
nofx, ты почему не используешь std::thread?
0
6 / 6 / 2
Регистрация: 27.08.2017
Сообщений: 28
02.09.2017, 21:18
Цитата Сообщение от nofx Посмотреть сообщение
В чем моя ошибка? Что не так
Нет проверки permission после захвата мьютекса (после 64-й и 86-й строк).
Погугли, как правильно делается double-checked locking.
0
Любитель чаепитий
 Аватар для GbaLog-
3745 / 1801 / 566
Регистрация: 24.08.2014
Сообщений: 6,020
Записей в блоге: 1
02.09.2017, 21:28
Цитата Сообщение от Ferrari F1 Посмотреть сообщение
ты почему не используешь std::thread?
1. это не всем доступное новшество.
2. как можно заметить, в коде ТС вообще ничего из с++ не используется.
0
6 / 6 / 2
Регистрация: 27.08.2017
Сообщений: 28
03.09.2017, 00:29
Цитата Сообщение от nofx Посмотреть сообщение
Что не так.
К предыдущему своему сообщению добавлю ещё, что тут присутству то, что называется https://en.wikipedia.org/wiki/... ime_of_use багом.
0
03.09.2017, 17:22

Не по теме:

Цитата Сообщение от GbaLog- Посмотреть сообщение
вообще ничего из с++ не используется
убили:rofl:

0
03.09.2017, 17:45

Не по теме:

Цитата Сообщение от ntlinuxnt Посмотреть сообщение
убили
ок, кроме std::cout ничего не используя и bool.
уже и забыл, что это в с++ появилось.
из современного с++ уж точно ничего не использовано...

0
807 / 534 / 158
Регистрация: 27.01.2015
Сообщений: 3,017
Записей в блоге: 1
03.09.2017, 17:46
ntlinuxnt, ну в принцапи да, тут сишня одна
0
03.09.2017, 18:15

Не по теме:

GbaLog-, Ferrari F1, Да я впринципе того же мнения, особенно когда такое вбивают в институтах под видом С++, а потом при виде нормальных плюсов впадают в ступор.

0
8 / 8 / 5
Регистрация: 28.10.2012
Сообщений: 135
03.09.2017, 22:52  [ТС]
Цитата Сообщение от Ferrari F1 Посмотреть сообщение
ntlinuxnt, ну в принцапи да, тут сишня одна
- да, не указал сразу что нужно использовать WinApi, а там "унылый" си си си
0
Ушел с форума
Эксперт С++
 Аватар для Убежденный
16481 / 7444 / 1187
Регистрация: 02.05.2013
Сообщений: 11,616
Записей в блоге: 1
03.09.2017, 23:11
В функции SetPermission и GetPermission передается указатель на HANDLE:
C++
1
2
3
treads1[i] = CreateThread(NULL, 0, &SetPermission, &prmsMuttex, 0, NULL);
// ...
treads2[i] = CreateThread(NULL, 0, &GetPermission, &prmsMuttex, 0, NULL);
Но берут они его как HANDLE, а не как указатель на HANDLE:
C++
1
2
3
4
DWORD WINAPI SetPermission(LPVOID lparam)
{
    CONST HANDLE mutex = (CONST HANDLE)lparam;
}
Чувствуешь разницу?

И вообще, надо проверять, что возвращают функции, а не просто дергать CreateThread,
WaitForXxx и т.д. и надеяться на успех. Например, не исключено, что WaitForSingleObject
внутри GetPermission или SetPermission вообще никогда не ждет и сразу возвращает
WAIT_FAILED с GetLastError = ERROR_INVALID_HANDLE...
1
8 / 8 / 5
Регистрация: 28.10.2012
Сообщений: 135
04.09.2017, 00:19  [ТС]
Цитата Сообщение от Убежденный Посмотреть сообщение
И вообще, надо проверять, что возвращают функции, а не просто дергать CreateThread,
WaitForXxx и т.д
- проверил, да, WaitForSingleObject была с ошибкой. Я переписал вызов на такой:

C++
1
2
3
treads1[i] = CreateThread(NULL, 0, &SetPermission, prmsMuttex, 0, NULL);
//..
treads2[i] = CreateThread(NULL, 0, &GetPermission, prmsMuttex, 0, NULL);
Цитата Сообщение от SeqInconsistent Посмотреть сообщение
Погугли, как правильно делается double-checked locking.
Почитал, интересно...Но я не пойму как это относится к этому коду - здесь же просто чекается булевская переменная параллельно, нету "new", нету синглтона никакого...
0
6 / 6 / 2
Регистрация: 27.08.2017
Сообщений: 28
04.09.2017, 01:35
Цитата Сообщение от nofx Посмотреть сообщение
Но я не пойму как это относится к этому коду - здесь же просто чекается булевская переменная параллельно, нету "new", нету синглтона никакого...
Double-checked locking применяется для эффективного создания синглтона. Но применение этого паттерна созданием синглтона не ограничивается.
Вместо создания синглтона одним тредом у тебя есть выдача разрешения одним тредом. Отличие в том, что разрешение забирается и может выдаваться снова, а синглтон только создаётся один раз. Но это отличие не существенно.
Главное, что есть действие, которое должно быть выполнено только одним тредом из нескольких и сделать это надо эффективно, не захватывая мьютекс когда действие заведомо делать не нужно. Для этого применяется double-checked locking. И в отличие от правильно сделанного double-checked locking у тебя есть проверка условия только до захвата мьютекса, а после захвата нету. А должна быть.
0
8 / 8 / 5
Регистрация: 28.10.2012
Сообщений: 135
06.09.2017, 08:46  [ТС]
Цитата Сообщение от SeqInconsistent Посмотреть сообщение
И в отличие от правильно сделанного double-checked locking у тебя есть проверка условия только до захвата мьютекса, а после захвата нету. А должна быть.
C++
1
2
3
4
DWORD wait_result = WaitForSingleObject(lparam, INFINITY);
        
        if (!permission)
            continue;
вставил double-cheked.

Добавлено через 14 минут
Убрал вывол в cout пониже. Понял, что потоки "конкурируют" за вывод. Ситуация чуть улучшилась.
C++
1
2
3
4
5
6
7
8
DWORD wait_result = WaitForSingleObject(lparam, INFINITY);
        
        if (permission)
            continue;
 
        permission = TRUE;
        
        ReleaseMutex(lparam);
Добавлено через 9 минут
П.С. При 4 потоках SetPermission и 4 - GetPermission более менее, но если их больше - то наблюдаются "двойные" set permission (т.е permission = TRUE)
0
807 / 534 / 158
Регистрация: 27.01.2015
Сообщений: 3,017
Записей в блоге: 1
06.09.2017, 08:56
nofx, мьютекс поставь перед местом конкурирования. (но это под сомнением, ибо я совершенно ничего о многопоточности (пока что) не знаю)
И вобще, ты почему берешься за работу с потоками совершенно ничего не читая и не зная о них?
0
6 / 6 / 2
Регистрация: 27.08.2017
Сообщений: 28
06.09.2017, 15:52
Лучший ответ Сообщение было отмечено nofx как решение

Решение

Цитата Сообщение от nofx Посмотреть сообщение
вставил double-cheked.
mutex стоит отпустить перед continue.
(И проверять что он захватывается, в первую очередь.)

Добавлено через 1 час 17 минут
Вот твой код, переписанный без ошибок

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
#include <Windows.h>
#include <cstdlib>
#include <iostream>
using namespace std;
 
#define THREADS1_NUMBER 5
#define THREADS2_NUMBER 5
 
DWORD WINAPI SetPermission(LPVOID lparam);
DWORD WINAPI GetPermission(LPVOID lparam);
VOID WINAPI UsePermission(LPVOID lparam);
 
volatile bool permission;
 
int main(int argc, char* argv[])
{
    HANDLE treads1[THREADS1_NUMBER];
    HANDLE treads2[THREADS1_NUMBER];
 
    HANDLE prmsMuttex = CreateMutex(NULL, FALSE, NULL);
 
    for (int i = 0; i < THREADS1_NUMBER; i++)
    {
        treads1[i] = CreateThread(NULL, 0, &SetPermission, prmsMuttex, 0, NULL);
    }
 
    for (int i = 0; i < THREADS2_NUMBER; i++)
    {
        treads2[i] = CreateThread(NULL, 0, &GetPermission, prmsMuttex, 0, NULL);
    }
 
    Sleep(5000);
 
    for (int i = 0; i < THREADS1_NUMBER; i++)
    {
        CloseHandle(treads1[i]);
    }
 
    for (int i = 0; i < THREADS2_NUMBER; i++)
    {
        CloseHandle(treads2[i]);
    }
 
    CloseHandle(prmsMuttex);
}
 
DWORD WINAPI SetPermission(LPVOID lparam)
{
    HANDLE mutex = lparam;
 
    while (true)
    {
        if (permission)
            continue;
 
        WaitForSingleObject(mutex, INFINITE);
 
        if (permission) {
            ReleaseMutex(mutex);
            continue;
        }
 
        cout << "Set permission " << GetCurrentThreadId() << endl;
        permission = TRUE;
 
        ReleaseMutex(mutex);
    }
 
}
 
DWORD WINAPI GetPermission(LPVOID lparam)
{
    HANDLE mutex = lparam;
 
    while (true)
    {
        if (!permission)
            continue;
 
        WaitForSingleObject(mutex, INFINITE);
 
        if (!permission) {
            ReleaseMutex(mutex);
            continue;
        }
 
        cout << "Get permission " << GetCurrentThreadId() << endl;
        permission = FALSE;
 
        UsePermission(NULL);
 
        ReleaseMutex(mutex);
    }
 
}
 
VOID WINAPI UsePermission(LPVOID lparam)
{
    cout << "call use_permission " << GetCurrentThreadId() << endl;
}
Помимо прочего, у тебя было INFINITY вместо INFINITE в WaitForSingleObject.

Добавлено через 5 минут
Но вообще стоит перейти на C++11+ мьютексы и атомики (и потоки).
1
Ушел с форума
Эксперт С++
 Аватар для Убежденный
16481 / 7444 / 1187
Регистрация: 02.05.2013
Сообщений: 11,616
Записей в блоге: 1
06.09.2017, 16:45
На самом деле для такой задачи не нужны мьютексы.
Мьютекс в Win32 - это объект ядра, его захват и освобождение, а тем более ожидание на нем,
являются очень дорогими операциями. Намного легче взять, например, критическую секцию или
даже сделать самопальный "лок":

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
LONG volatile g_Lock = 0;
 
DWORD WINAPI SetPermission(LPVOID lparam)
{
    while (true)
    {
        if (0 == _InterlockedCompareExchange(&g_Lock, 1, 0))
        {
            printf("Set permission %lu\r\n", GetCurrentThreadId());
            _InterlockedExchange(&g_Lock, 2);
        }
    }
 
    return 0;
}
 
DWORD WINAPI GetPermission(LPVOID lparam)
{
    while (true)
    {
        if (2 == _InterlockedCompareExchange(&g_Lock, 3, 2))
        {
            printf("Get permission %lu\r\n", GetCurrentThreadId());
            UsePermission(NULL);
            _InterlockedExchange(&g_Lock, 0);
        }
    }
 
    return 0;
}
Ну а запущенные потоки необходимо останавливать, посылая им какой-либо
сигнал (например, SetEvent) и затем дожидаясь их полной остановки (WaitForXxx).
Иначе поведение процесса, особенно при завершении, будет неопределенным.
1
8 / 8 / 5
Регистрация: 28.10.2012
Сообщений: 135
07.09.2017, 08:50  [ТС]
Цитата Сообщение от Ferrari F1 Посмотреть сообщение
И вобще, ты почему берешься за работу с потоками совершенно ничего не читая и не зная о них?
- проходил собеседование

Добавлено через 30 минут
Цитата Сообщение от SeqInconsistent Посмотреть сообщение
Но вообще стоит перейти на C++11+ мьютексы и атомики (и потоки).
- нужно было только на winapi функциях
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
07.09.2017, 08:50
Помогаю со студенческими работами здесь

работа с функциями.что-то не так.
выдает ошибку: неоднозначный вызов перегруженной функции. в чем дело? #include &quot;stdafx.h&quot; #include &lt;iostream&gt; ...

Что здесь не так? (Работа с файлами)
И снова здрасьте, написал процедурку, которая проверяет 1 или 0 находится в файле, что-бы понять, можно проигрывать музыку или нет. Однако...

Работа над циклами. Не пойму что не так
Добрый день! Условие задачи звучит следующим образом : Найти сумму 11 членов ряда, в котором \Large...

Работа с указателями: подскажите что я не так делаю
Добрый день Подскажите пожалуйста что в этой программе не так #include &lt;iostream&gt; using namespace std; void...

Не так работает многопоточность сервера и клиента
Здравствуйте! Мне дана следующая задача. Сервер создаёт n процессов, указывая для каждого время его жизни в секундах. Должно быть...


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

Или воспользуйтесь поиском по форуму:
18
Ответ Создать тему
Новые блоги и статьи
Изучаю kubernetes
lagorue 13.01.2026
А пригодятся-ли мне знания kubernetes в России?
Сукцессия микоризы: основная теория в виде двух уравнений.
anaschu 11.01.2026
https:/ / rutube. ru/ video/ 7a537f578d808e67a3c6fd818a44a5c4/
WordPad для Windows 11
Jel 10.01.2026
WordPad для Windows 11 — это приложение, которое восстанавливает классический текстовый редактор WordPad в операционной системе Windows 11. После того как Microsoft исключила WordPad из. . .
Classic Notepad for Windows 11
Jel 10.01.2026
Old Classic Notepad for Windows 11 Приложение для Windows 11, позволяющее пользователям вернуть классическую версию текстового редактора «Блокнот» из Windows 10. Программа предоставляет более. . .
Почему дизайн решает?
Neotwalker 09.01.2026
В современном мире, где конкуренция за внимание потребителя достигла пика, дизайн становится мощным инструментом для успеха бренда. Это не просто красивый внешний вид продукта или сайта — это. . .
Модель микоризы: классовый агентный подход 3
anaschu 06.01.2026
aa0a7f55b50dd51c5ec569d2d10c54f6/ O1rJuneU_ls https:/ / vkvideo. ru/ video-115721503_456239114
Owen Logic: О недопустимости использования связки «аналоговый ПИД» + RegKZR
ФедосеевПавел 06.01.2026
Owen Logic: О недопустимости использования связки «аналоговый ПИД» + RegKZR ВВЕДЕНИЕ Введу сокращения: аналоговый ПИД — ПИД регулятор с управляющим выходом в виде числа в диапазоне от 0% до. . .
Модель микоризы: классовый агентный подход 2
anaschu 06.01.2026
репозиторий https:/ / github. com/ shumilovas/ fungi ветка по-частям. коммит Create переделка под биомассу. txt вход sc, но sm считается внутри мицелия. кстати, обьем тоже должен там считаться. . . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru