# -*- coding: windows-1251 -*-
import threading
import random
import time

# Dining philosophers
# 5 мудрецов и 5 вилок для лапши. Для еды мудрецу нужно 2 вилки.
# Для устранения дедлока одна вилка отдается, если вторая не захватывается.
# Для этого захватывается первая вилка (lock), а за второй производится попытка 
# захвата без блокировки. Если попытка неудачная, то перваая вилка отпускается,
# переключается (swap) порядок захвата, и теперь начинаем захват с другой стороны.

class Philosopher(threading.Thread):

    running = True

    def __init__(self, xname, forkOnLeft, forkOnRight):
        threading.Thread.__init__(self)
        self.name = xname
        self.forkOnLeft = forkOnLeft
        self.forkOnRight = forkOnRight

    def run(self):
        while(self.running):
            # Теперь мудрец думает (т.е. процесс засыпает).
            time.sleep(random.uniform(3,7))
            print (self.name, 'голодный.')
            self.dine()

    def dine(self):
        fork1, fork2 = self.forkOnLeft, self.forkOnRight

        while self.running:
            fork1.acquire(True)
            locked = fork2.acquire(True)
            # это секция против дедлока  vvvv
            #if locked: break
            #fork1.release()
			# это секция против дедлока  ^^^^
			# 
			# повышение эффективности процесса  vvvv
            #print (self.name, 'поменял порядок захвата.')
            #fork1, fork2 = fork2, fork1
            # повышение эффективности процесса ^^^^
        else:
            return

        self.dining()
	    # Теперь мудрец наелся (т.е. процесс освободил ресурсы).
        fork2.release()
        fork1.release()

    def dining(self):
	    # Теперь мудрец ест (т.е. процесс захватил ресурсы).
        print (self.name, 'начал есть.')
        time.sleep(random.uniform(2,5))
        print (self.name, 'наелся и начал думать.')

def DiningPhilosophers(numfilos):
    if numfilos < 3:
       print('Число мудрецов от 3 до 11!')
       return
    # создание семафоров ресурсов (вилочек, forks) в виде мьютексов
    forks = [threading.Lock() for n in range(numfilos)]

    philosopherNames = ('1:Кант:','2:Маркс:','3:Платон:','4:Руссо:','5:Сократ:',
                        '6:Пифагор:','7:Гегель:','8:Вольтер:','9:Декарт:','10:ЛаоЦзы:','11:Рассел:')
    # список имен по-английски
    #philosopherNames = ('1:Kant:','2:Marx:','3:Plato:','4:Russo:','5:Sockrat:',
    #   '6:Pifagor:','7:Gheghel:','8:Voltair:','9:Dekart:','10:Lao:','11:Russel:')

    philosophers = [Philosopher(philosopherNames[i], forks[i%numfilos],
                                forks[(i+1)%numfilos]) for i in range(numfilos)]

    random.seed(5719)
    Philosopher.running = True
    for p in philosophers:
        p.start()
    time.sleep(50)
    Philosopher.running = False
    print ("== Все закончили! ==")

DiningPhilosophers(7)
