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

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

11.03.2014, 00:58. Показов 4086. Ответов 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
Ответ Создать тему
Новые блоги и статьи
http://iceja.net/ математические сервисы
iceja 20.01.2026
Обновила свой сайт http:/ / iceja. net/ , приделала Fast Fourier Transform экстраполяцию сигналов. Однако предсказывает далеко не каждый сигнал (см ограничения http:/ / iceja. net/ fourier/ docs ). Также. . .
http://iceja.net/ сервер решения полиномов
iceja 18.01.2026
Выкатила http:/ / iceja. net/ сервер решения полиномов (находит действительные корни полиномов методом Штурма). На сайте документация по API, но скажу прямо VPS слабенький и 200 000 полиномов. . .
Расчёт переходных процессов в цепи постоянного тока
igorrr37 16.01.2026
/ * Дана цепь постоянного тока с R, L, C, k(ключ), U, E, J. Программа составляет систему уравнений по 1 и 2 законам Кирхгофа, решает её и находит переходные токи и напряжения на элементах схемы. . . .
Восстановить юзерскрипты Greasemonkey из бэкапа браузера
damix 15.01.2026
Если восстановить из бэкапа профиль Firefox после переустановки винды, то список юзерскриптов в Greasemonkey будет пустым. Но восстановить их можно так. Для этого понадобится консольная утилита. . .
Сукцессия микоризы: основная теория в виде двух уравнений.
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
В современном мире, где конкуренция за внимание потребителя достигла пика, дизайн становится мощным инструментом для успеха бренда. Это не просто красивый внешний вид продукта или сайта — это. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru