Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.56/18: Рейтинг темы: голосов - 18, средняя оценка - 4.56
9 / 9 / 10
Регистрация: 05.09.2013
Сообщений: 502

Задача о философах с использованием событий

11.03.2014, 00:58. Показов 4127. Ответов 13
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Пытаюсь разобраться с этой задачей .
Задача: за круглым столом сидят философы. Их жизненный цикл состоит из двух состояний: ест и думает. Ест он двумя вилками - правой и левой, а вилки расположены не каждому по две, а между каждыми двумя философами по одной. Когда один ест - вилки вокруг него блокируются событиями, а если хотя бы одна из вилок занята - он просто забивает на еду и начинает думать.
Поискал в интернете и нашёл такой пример:
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
#include "stdafx.h"
#include "windows.h"
#include "conio.h"
#include "stdlib.h"
 
#define min 100
#define max 500
#define step 4
#define kol 5
 
HANDLE some[kol]; 
HANDLE Philosopher[kol];
 
LPTHREAD_START_ROUTINE WINAPI philosopher(LPVOID arg)
{
    int left_fork = (int)arg, right_fork = left_fork+1;
 
    for(int i = 0; i < step; i++)   //повторяет 4 раза
    {
        Sleep(min + rand()%(max-min)); //задержка
        printf("Philosopher[%i] want to eat.\n", left_fork);
        printf("Try to cath forks.\n");
        printf("Left[%i] and right[%i] forks - ", left_fork, right_fork);
        //проверка вилок
        if (WaitForSingleObject(some[left_fork], 1) != WAIT_OBJECT_0 &
            WaitForSingleObject(some[right_fork], 1) != WAIT_OBJECT_0) 
        {
            printf("success.\n");
            SetEvent(some[left_fork]);  //объект "событие" в сигнальное состояние
            SetEvent(some[right_fork]); //объект "событие" в сигнальное состояние
            printf("Eating.");          //философ ест
            Sleep(min + rand()%(max-min));
            ResetEvent(some[left_fork]); //сброс события
            ResetEvent(some[right_fork]);//сброс события
        }
        else printf("failed.\n");       //философу не удалось поесть
 
        Sleep(min + rand()%(max-min));
        printf("Philosopher[%i] THINKING.\n", left_fork); //философ думает
    }
  
 
    return 0;
}
 
int _tmain(int argc, _TCHAR* argv[])
{
    for (int i = 0; i <kol; i++)
    {
        some[i] = CreateEvent(NULL, TRUE, TRUE, NULL); //тип сброса- ручной
        ResetEvent(some[i]);
    }
    for (int i = 0; i < kol; i++)
    {
        Philosopher[i] = CreateThread(NULL, 0, philosopher((LPVOID)i), NULL, 0, NULL);
    }
    return 0;
}
Но он вылетает , после того , как 1-ый философ закончит. То ест , ко 2-ому дело не доходит .
Вроде всё более менее понятно , кроме пару моментов: каким образом задаются значения левой и правой вилки ? написано -
C++
1
 int left_fork = (int)arg, right_fork = left_fork+1;
- что это означает , понять не могу
0
Лучшие ответы (1)
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
11.03.2014, 00:58
Ответы с готовыми решениями:

Задача о философах
Даны 5 философов, сидящих в круг, и 5 вилок. Каждый из них может: думать, брать правую вилку, брать левую вилку, есть, класть правую,...

Задача об обедающих философах
Тема заезженная,но все таки. Интересует решение задачи &quot;Обедающих философов&quot;. Мне надо сделать решение этой задачи на формах...

Задача об обедающих философах
Доброго времени суток! Поиском пользовался, но ответа для себя не нашёл, поэтому создаю тему. Имеется задача об обедающих философах....

13
 Аватар для Toshkarik
1181 / 894 / 94
Регистрация: 03.08.2011
Сообщений: 2,461
11.03.2014, 01:11
Чтоб было более понятно:

C++
1
2
int left_fork  = reinterpret_cast< int >( arg );
int right_fork = left_fork + 1;
В последнем потоке будут проблемы, так как right_fork будет равен 5, и будет обращение к some[ 5 ], а это выход за пределы.

Добавлено через 4 минуты
Так же нужно использовать WaitForMultipleObjects в условии.
1
9 / 9 / 10
Регистрация: 05.09.2013
Сообщений: 502
11.03.2014, 01:25  [ТС]
Спасибо, понял , просто запутано написано было

Да это я тоже заметил , и как раз после обращения к some[ 5 ] вылетает эксепшн
может есть какой-то выход из этой ситуации ? может можно поставить какой-то ограничитель ?

Добавлено через 11 минут
а зачем WaitForMultipleObjects ? я когда изучал события , там использовалось WaitForSingleObject
прочитал про WaitForMultipleObjects - вообще не пойму , какие ему параметры передавать нужно

DWORD WaitForMultipleObjects(
DWORD nCount, // число объектов в массиве lpHandles
CONST HANDLE *lpHandles, // указатель на массив описателей объектов ядра
BOOL bWaitAll, // флаг, означающей надо ли дожидаться всех объектов или достаточно одного
DWORD dwMilliseconds // таймаут
);
0
 Аватар для Toshkarik
1181 / 894 / 94
Регистрация: 03.08.2011
Сообщений: 2,461
11.03.2014, 01:35
Просто у последнего потока должно быть some[ 4 ] для левой вилки, и some[ 0 ] для правой. Лучше передавай в качестве аргумента структуру с параметрами:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
struct ThreadArgs {
   HANDLE forks[ 2 ];
};
 
...
 
ThreadArgs args;
...
args.forks[ 0 ] = some[ i ];
 
if ( i < 4 )
   args.forks[ 1 ] = some[ i + 1 ];
else
   args.forks[ 1 ] = some[ 0 ];
 
Philosopher[i] = CreateThread( NULL, 0, philosopher, static_cast< void * >( &args ), 0, NULL );
...
Кстати, вообще не понятно что это за программа, в CreateThread 3 параметром должен передаваться указатель на функцию, а здесь передается результат функции philosopher, которая всегда возвращает 0. Параметр для этой функции должен передаваться пятым. Тут нет никакой многопоточности. Попробую сейчас исправить для вас, чтоб было попроще.
1
9 / 9 / 10
Регистрация: 05.09.2013
Сообщений: 502
11.03.2014, 01:49  [ТС]
Да я просто пока только начинаю всё это учить , может какие-то моменты не могу понять, хотя пытаюсь )

можете помочь , и объяснить , что к чему , пожалуйста ? если я сейчас начну туда ещё и структуру лепить , то вообще запутаюсь )

Добавлено через 8 минут
я так понял , что в
C++
1
2
3
struct ThreadArgs {
   HANDLE forks[ 2 ];
};
forks[2] - это вместо
C++
1
 int left_fork = (int)arg, right_fork = left_fork+1;
?

и в мейне будет :
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
int _tmain(int argc, _TCHAR* argv[])
{ThreadArgs args;
 
  for (int i = 0; i <kol; i++)
    {
        some[i] = CreateEvent(NULL, TRUE, TRUE, NULL); //тип сброса- ручной
        ResetEvent(some[i]);
    }
    for (int i = 0; i < kol; i++)
    {
        args.forks[ 0 ] = some[ i ];
 
if ( i < 4 )
   args.forks[ 1 ] = some[ i + 1 ];
else
   args.forks[ 1 ] = some[ 0 ];
 
Philosopher[i] = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE) philosopher, static_cast< void * >( &args ), 0, NULL );
    }
    return 0;
}
0
 Аватар для Toshkarik
1181 / 894 / 94
Регистрация: 03.08.2011
Сообщений: 2,461
11.03.2014, 02:10
Лучший ответ Сообщение было отмечено NNN7 как решение

Решение

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
#include <windows.h>
#include <cstdlib>
#include <cstdio>
 
#define min 100
#define max 500
#define step 4
 
struct ThreadArgs {
   int philosopherNum;
   HANDLE forks[ 2 ];
};
 
DWORD philosopherAction( LPVOID arg );
 
int main() {
   const unsigned int PHILOSOPHERS_NUM = 5;
   
   HANDLE forks[ PHILOSOPHERS_NUM ] = {};
   HANDLE philosophers[ PHILOSOPHERS_NUM ] = {};
   
   ThreadArgs args;
   
   for ( unsigned int i = 0; i < PHILOSOPHERS_NUM; i++ ) {
      forks[ i ] = CreateEvent( 0, true, false, NULL ); //тип сброса- ручной
   }
   
   for ( unsigned int i = 0; i < PHILOSOPHERS_NUM; i++) {
      args.philosopherNum = i;
      args.forks[ 0 ] = forks[ i ];
      
      if ( i < 4 )
         args.forks[ 1 ] = forks[ i + 1 ];
      else
         args.forks[ 1 ] = forks[ 0 ];
      
      philosophers[ i ] = CreateThread( NULL, 0, philosopherAction, &args, 0, NULL );
   }
   
   WaitForMultipleObjects( PHILOSOPHERS_NUM, philosophers, true, INFINITE );
   
   return 0;
}
 
DWORD philosopherAction( LPVOID arg ) {
   ThreadArgs *args = static_cast< ThreadArgs * >( arg );
 
    for(int i = 0; i < step; i++) {          //повторяет 4 раза
        Sleep( min + rand() % ( max-min ));  //задержка
        printf( "Philosopher[ %i ] want to eat.\n", args->philosopherNum );
        printf( "Try to cath forks.\n");
        printf( "Left[%i] and right[%i] forks - ", args->philosopherNum, args->philosopherNum + 1 );
        
        if ( WaitForMultipleObjects( 2, args->forks, true, 1 ) != WAIT_OBJECT_0 ) {
            printf("success.\n");
            SetEvent( args->forks[ 0 ] );  //объект "событие" в сигнальное состояние
            SetEvent( args->forks[ 1 ] );  //объект "событие" в сигнальное состояние
            printf( "Eating." );           //философ ест
            Sleep( min + rand() % ( max - min ));
            ResetEvent( args->forks[ 0 ] );   //сброс события
            ResetEvent( args->forks[ 1 ] );   //сброс события
        }
        
        Sleep( min + rand() % ( max-min ));
        
        printf("Philosopher[%i] THINKING.\n", args->philosopherNum ); //философ думает
    }
    
    return 0;
}
Попытался хоть что то оставить от предыдущего примера. Сразу говорю - в выводе будет каша, так как одновременно будут писать все потоки.

Добавлено через 1 минуту
NNN7, да, вы правильно все поняли. Только вот в примере каша, прототип функции не соответствует ожидаемому в качестве параметра.

Добавлено через 4 минуты
WaitForMultipleObjects( PHILOSOPHERS_NUM, philosophers, true, INFINITE ); нужен для того, что бы основной поток дождался завершения всех дочерних потоков.
Первым параметром идет количество объектов в массиве, вторым идет указатель на массив объектов, третьим - флаг - ждать ли сигнала от всех объектов ( true ) или хватит одного сигнала ( false ). Ну и последним - количество миллисекунд для ожидания.

Вот, кстати, очень хорошая статья о многопоточности в целом, и о ней же в Windows в частности http://www.kurzenkov.com/artic... ding1.html
1
9 / 9 / 10
Регистрация: 05.09.2013
Сообщений: 502
11.03.2014, 02:23  [ТС]
Спасибо большое . Правда я сейчас сразу так и не разберусь , много непонятного
извините , не пойму , что это означает :
C++
1
2
HANDLE forks[ PHILOSOPHERS_NUM ] = {};
   HANDLE philosophers[ PHILOSOPHERS_NUM ] = {};
зачем там фигурные скобки и почему в структуре объявляем
C++
1
HANDLE forks[ 2 ];
а в мейне поменяли на 5 ?
я , наверное , Вас , уже достал)

Добавлено через 8 минут
ну да , в выводе , получается , что только 1 из философ действует
а почему пишут все потоки ?
0
 Аватар для Toshkarik
1181 / 894 / 94
Регистрация: 03.08.2011
Сообщений: 2,461
11.03.2014, 02:29
HANDLE forks[ PHILOSOPHERS_NUM ] - это массив дескрипторов объектов события, ранее он назывался some[]. Я его переименовал и убрал в основную функцию из глобально области.

HANDLE philosophers[ PHILOSOPHERS_NUM ] - это массив дескрипторов потоков, ранее он назывался Philosopher[], я его так же переименовал и перенес в основную функцию из глобально области.

const unsigned int PHILOSOPHERS_NUM - это количество философов. Ранее это был define и назывался kol, я просто переименовал, и сделал его константой переменной. Количество вилок совпадает с количество философов по условию.

Фигурные скобки нужны для того, что бы элементы массива инициализировались нулями. Иначе там был бы мусор, будет работать и без этого, просто это предосторожность.

В структуре forks[ 2 ] - это массив для объектов события, для левой и правой вилок. Сделал массивом для того, чтобы легче было передавать в WaitForMultipleObjects.

Цитата Сообщение от NNN7 Посмотреть сообщение
я , наверное , Вас , уже достал)
Совсем нет. Форум для этого и нужен. И я свои знания проверяю и укрепляю .

Добавлено через 2 минуты
Цитата Сообщение от NNN7 Посмотреть сообщение
а почему пишут все потоки ?
Потому что в них во всех используется printf, и они выполняются параллельно
0
9 / 9 / 10
Регистрация: 05.09.2013
Сообщений: 502
11.03.2014, 02:58  [ТС]
Спасибо! Не думал , что Вы так распишите

Буду пробовать осмысливать всё дальше)
Спасибо Вам ещё раз!
0
 Аватар для Toshkarik
1181 / 894 / 94
Регистрация: 03.08.2011
Сообщений: 2,461
11.03.2014, 03:27
Кстати, я тут ошибку сделал, именно поэтому вы видите, что только 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
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
#include <windows.h>
#include <cstdlib>
#include <cstdio>
 
#define min 100
#define max 500
#define step 4
 
struct ThreadArgs {
   int philosopherNum;
   HANDLE forks[ 2 ];
};
 
DWORD philosopherAction( LPVOID arg );
 
CRITICAL_SECTION csFlag;
 
void output( const char *msg ) {
   EnterCriticalSection( &csFlag );
   printf( msg );
   LeaveCriticalSection( &csFlag );
}
 
void output( const char *msg, int arg1 ) {
   EnterCriticalSection( &csFlag );
   printf( msg, arg1 );
   LeaveCriticalSection( &csFlag );
}
 
void output( const char *msg, int arg1, int arg2 ) {
   EnterCriticalSection( &csFlag );
   printf( msg, arg1, arg2 );
   LeaveCriticalSection( &csFlag );
}
 
int main() {
   const unsigned int PHILOSOPHERS_NUM = 5;
   
   HANDLE forks[ PHILOSOPHERS_NUM ] = {};
   HANDLE philosophers[ PHILOSOPHERS_NUM ] = {};
   
   ThreadArgs args[ PHILOSOPHERS_NUM ];
   
   InitializeCriticalSection( &csFlag );
   
   for ( unsigned int i = 0; i < PHILOSOPHERS_NUM; i++ ) {
      forks[ i ] = CreateEvent( 0, true, false, NULL ); //тип сброса- ручной
   }
   
   for ( unsigned int i = 0; i < PHILOSOPHERS_NUM; i++) {
      args[ i ].philosopherNum = i;
      args[ i ].forks[ 0 ] = forks[ i ];
      
      if ( i < 4 )
         args[ i ].forks[ 1 ] = forks[ i + 1 ];
      else
         args[ i ].forks[ 1 ] = forks[ 0 ];
      
      philosophers[ i ] = CreateThread( NULL, 0, philosopherAction, &args[ i ], 0, NULL );
   }
   
   WaitForMultipleObjects( PHILOSOPHERS_NUM, philosophers, true, INFINITE );
   
   DeleteCriticalSection( &csFlag );
   
   return 0;
}
 
DWORD philosopherAction( LPVOID arg ) {
   ThreadArgs *args = static_cast< ThreadArgs * >( arg );
   
   for(int i = 0; i < step; i++) {          //повторяет 4 раза
      Sleep( min + rand() % ( max-min ));  //задержка
      output( "Philosopher[ %i ] want to eat.\n", args->philosopherNum );
      output( "Try to catch forks.\n");
      output( "Left[%i] and right[%i] forks - ", args->philosopherNum, args->philosopherNum + 1 );
      
      if ( WaitForMultipleObjects( 2, args->forks, true, 1 ) != WAIT_OBJECT_0 ) {
         SetEvent( args->forks[ 0 ] );          //объект "событие" в сигнальное состояние
         SetEvent( args->forks[ 1 ] );          //объект "событие" в сигнальное состояние
         output( "Eating." );                   //философ ест
         Sleep( min + rand() % ( max - min ));
         ResetEvent( args->forks[ 0 ] );        //сброс события
         ResetEvent( args->forks[ 1 ] );        //сброс события
      }
      
      Sleep( min + rand() % ( max-min ));
      
      output( "Philosopher[%i] THINKING.\n", args->philosopherNum ); //философ думает
   }
   
   return 0;
}
1
9 / 9 / 10
Регистрация: 05.09.2013
Сообщений: 502
11.03.2014, 11:19  [ТС]
Спасибо!
Можете объяснить , что и как ? Я так понял , ввели ещё и критические секции
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void output( const char *msg ) {
   EnterCriticalSection( &csFlag );
   printf( msg );
   LeaveCriticalSection( &csFlag );
}
 
void output( const char *msg, int arg1 ) {
   EnterCriticalSection( &csFlag );
   printf( msg, arg1 );
   LeaveCriticalSection( &csFlag );
}
 
void output( const char *msg, int arg1, int arg2 ) {
   EnterCriticalSection( &csFlag );
   printf( msg, arg1, arg2 );
   LeaveCriticalSection( &csFlag );
}
зачем аж три функции с разными параметрами ? и что там вообще происходит?)

Добавлено через 1 час 9 минут
и вот здесь запутался уже
C++
1
2
3
 for ( unsigned int i = 0; i < PHILOSOPHERS_NUM; i++) {
      args.philosopherNum = i;
      args.forks[ 0 ] = forks[ i ];
0
 Аватар для Toshkarik
1181 / 894 / 94
Регистрация: 03.08.2011
Сообщений: 2,461
11.03.2014, 12:13
Я на быструю руку написал 3 функции потому что используются 3 printf с разным количеством параметров. Они просто для удобства. Можно было прям в функции потока обернуть все printf в
C++
1
2
3
EnterCriticalSection( &csFlag );
...
LeaveCriticalSection( &csFlag );
Это помогает сделать так, что бы одновременно выполнялась только одна функция printf.

Цитата Сообщение от NNN7 Посмотреть сообщение
и вот здесь запутался уже
Что именно не понятно?
args.philosopherNum - это номер философа ( потока ). Или что то другое?
0
9 / 9 / 10
Регистрация: 05.09.2013
Сообщений: 502
11.03.2014, 15:40  [ТС]
а почему разное кол-во параметров? вроде ж для всех философов одинаково всё

и задача , получается , использует и события , и критические секции

Добавлено через 3 часа 16 минут
а можно ли как-то без критических секций?
0
 Аватар для Toshkarik
1181 / 894 / 94
Регистрация: 03.08.2011
Сообщений: 2,461
12.03.2014, 11:18
Конечно, можно. Я добавил ее для того, что бы вывод не перемешивался. Уберите ее, будет все работать точно также, но вывод будет перемешан.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
12.03.2014, 11:18
Помогаю со студенческими работами здесь

Многопоточность: задача об обедающих философах
Доброго времени суток! Нужно перевести код с С++ с использованием библиотеки &lt;thread&gt; и &lt;mutex&gt; на WinAPI. Программа...

Многопоточность, задача об обедающих философах (семафоры)
#include &quot;iostream&quot; #include &quot;string&quot; #include &quot;windows.h&quot; #include &quot;process.h&quot; #include &lt;conio.h&gt; using namespace std; ...

Задача об обедающих философах [C++|Linux|ARM Mitel5000]
Всем привет) Собственно несколько дней я ковыряюсь с проблемой и не знаю как её решить) Условия задачи: За круглым столом расставлены...

Правильная обработка событий с использованием .on()
Разрешите, пожалуйста, взрыв мозга. Есть php-страница, к ней подключается javascript внешним файлом. В нём конструкция вида ...

Написать код с использованием событий и делегатов
Подскажите, как правильно реализовать следующую задачу: Есть класс Man: public class Man { public Man(string...


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

Или воспользуйтесь поиском по форуму:
14
Ответ Создать тему
Новые блоги и статьи
Модель заражения группы наркоманов
alhaos 17.04.2026
Условия задачи сформулированы тут Суть: - Группа наркоманов из 10 человек. - Только один инфицирован ВИЧ. - Колются одной иглой. - Колются раз в день. - Колются последовательно через. . .
Мысли в слух. Про "навсегда".
kumehtar 16.04.2026
Подумалось тут, что наверное очень глупо использовать во всяких своих установках понятие "навсегда". Это очень сильное понятие, и я только начинаю понимать край его смысла, не смотря на то что давно. . .
My Business CRM
MaGz GoLd 16.04.2026
Всем привет, недавно возникла потребность создать CRM, для личных нужд. Собственно программа предоставляет из себя базу данных клиентов, в которой можно фиксировать звонки, стадии сделки, а также. . .
Знаешь почему 90% людей редко бывают счастливыми?
kumehtar 14.04.2026
Потому что они ждут. Ждут выходных, ждут отпуска, ждут удачного момента. . . а удачный момент так и не приходит.
Фиксация колонок в отчете СКД
Maks 14.04.2026
Фиксация колонок в СКД отчета типа Таблица. Задача: зафиксировать три левых колонки в отчете. Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка) / / . . .
Настройки VS Code
Loafer 13.04.2026
{ "cmake. configureOnOpen": false, "diffEditor. ignoreTrimWhitespace": true, "editor. guides. bracketPairs": "active", "extensions. ignoreRecommendations": true, . . .
Оптимизация кода на разграничение прав доступа к элементам формы
Maks 13.04.2026
Алгоритм из решения ниже реализован на нетиповом документе, разработанного в конфигурации КА2. Задачи, как таковой, поставлено не было, проделанное ниже исключительно моя инициатива. Было так:. . .
Контроль заполнения и очистка дат в зависимости от значения перечислений
Maks 12.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "ПланированиеПерсонала", разработанного в конфигурации КА2. Задача: реализовать контроль корректности заполнения дат назначения. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru