Форум программистов, компьютерный форум CyberForum.ru

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

Восстановить пароль Регистрация
 
NNN7
7 / 7 / 3
Регистрация: 05.09.2013
Сообщений: 503
11.03.2014, 00:58     Задача о философах с использованием событий #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
#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;
- что это означает , понять не могу
Лучшие ответы (1)
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
11.03.2014, 00:58     Задача о философах с использованием событий
Посмотрите здесь:

задача с использованием функций! C++
Задача с использованием цикла for C++
Задача с использованием функций строк в С++ C++
Задача с использованием функций C++
C++ Задача с использованием последовательности
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Toshkarik
 Аватар для Toshkarik
1139 / 856 / 50
Регистрация: 03.08.2011
Сообщений: 2,381
Завершенные тесты: 1
11.03.2014, 01:11     Задача о философах с использованием событий #2
Чтоб было более понятно:

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

Добавлено через 4 минуты
Так же нужно использовать WaitForMultipleObjects в условии.
NNN7
7 / 7 / 3
Регистрация: 05.09.2013
Сообщений: 503
11.03.2014, 01:25  [ТС]     Задача о философах с использованием событий #3
Спасибо, понял , просто запутано написано было

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

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

DWORD WaitForMultipleObjects(
DWORD nCount, // число объектов в массиве lpHandles
CONST HANDLE *lpHandles, // указатель на массив описателей объектов ядра
BOOL bWaitAll, // флаг, означающей надо ли дожидаться всех объектов или достаточно одного
DWORD dwMilliseconds // таймаут
);
Toshkarik
 Аватар для Toshkarik
1139 / 856 / 50
Регистрация: 03.08.2011
Сообщений: 2,381
Завершенные тесты: 1
11.03.2014, 01:35     Задача о философах с использованием событий #4
Просто у последнего потока должно быть 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. Параметр для этой функции должен передаваться пятым. Тут нет никакой многопоточности. Попробую сейчас исправить для вас, чтоб было попроще.
NNN7
7 / 7 / 3
Регистрация: 05.09.2013
Сообщений: 503
11.03.2014, 01:49  [ТС]     Задача о философах с использованием событий #5
Да я просто пока только начинаю всё это учить , может какие-то моменты не могу понять, хотя пытаюсь )

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

Добавлено через 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;
}
Toshkarik
 Аватар для Toshkarik
1139 / 856 / 50
Регистрация: 03.08.2011
Сообщений: 2,381
Завершенные тесты: 1
11.03.2014, 02:10     Задача о философах с использованием событий #6
Сообщение было отмечено автором темы, экспертом или модератором как ответ
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/articles/multithreading1.html
NNN7
7 / 7 / 3
Регистрация: 05.09.2013
Сообщений: 503
11.03.2014, 02:23  [ТС]     Задача о философах с использованием событий #7
Спасибо большое . Правда я сейчас сразу так и не разберусь , много непонятного
извините , не пойму , что это означает :
C++
1
2
HANDLE forks[ PHILOSOPHERS_NUM ] = {};
   HANDLE philosophers[ PHILOSOPHERS_NUM ] = {};
зачем там фигурные скобки и почему в структуре объявляем
C++
1
HANDLE forks[ 2 ];
а в мейне поменяли на 5 ?
я , наверное , Вас , уже достал)

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

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

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

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

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

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

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

Буду пробовать осмысливать всё дальше)
Спасибо Вам ещё раз!
Toshkarik
 Аватар для Toshkarik
1139 / 856 / 50
Регистрация: 03.08.2011
Сообщений: 2,381
Завершенные тесты: 1
11.03.2014, 03:27     Задача о философах с использованием событий #10
Кстати, я тут ошибку сделал, именно поэтому вы видите, что только 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;
}
NNN7
7 / 7 / 3
Регистрация: 05.09.2013
Сообщений: 503
11.03.2014, 11:19  [ТС]     Задача о философах с использованием событий #11
Спасибо!
Можете объяснить , что и как ? Я так понял , ввели ещё и критические секции
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 ];
Toshkarik
 Аватар для Toshkarik
1139 / 856 / 50
Регистрация: 03.08.2011
Сообщений: 2,381
Завершенные тесты: 1
11.03.2014, 12:13     Задача о философах с использованием событий #12
Я на быструю руку написал 3 функции потому что используются 3 printf с разным количеством параметров. Они просто для удобства. Можно было прям в функции потока обернуть все printf в
C++
1
2
3
EnterCriticalSection( &csFlag );
...
LeaveCriticalSection( &csFlag );
Это помогает сделать так, что бы одновременно выполнялась только одна функция printf.

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

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

Добавлено через 3 часа 16 минут
а можно ли как-то без критических секций?
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
12.03.2014, 11:18     Задача о философах с использованием событий
Еще ссылки по теме:

Задача с использованием процедур C++
Задача с использованием struct C++
C++ Задача C++ с использованием цикла

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

Или воспользуйтесь поиском по форуму:
Toshkarik
 Аватар для Toshkarik
1139 / 856 / 50
Регистрация: 03.08.2011
Сообщений: 2,381
Завершенные тесты: 1
12.03.2014, 11:18     Задача о философах с использованием событий #14
Конечно, можно. Я добавил ее для того, что бы вывод не перемешивался. Уберите ее, будет все работать точно также, но вывод будет перемешан.
Yandex
Объявления
12.03.2014, 11:18     Задача о философах с использованием событий
Ответ Создать тему
Опции темы

Текущее время: 09:16. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru