# cPy - demonstrating pre-emtive multi processing
# Provided by Anthony Vogelaar, Perth Scotland
# rev 0.10  2024-06-04  initial release

# remark: use psutil to set cpu affinity

import  os;             os.system('clear')
import  time
import  threading
import  multiprocessing

# ========================= Multi processing ==========================

def demo1():

    def task(ch, delay, count):
        print(f'\n{ch} my process_id is: {os.getpid()}')
        for i in range(count):
            print(ch, end='', flush=True)
            time.sleep(delay)


    print(f'my process_id is: {os.getpid()}')
    t1 = multiprocessing.Process(target=task, args=('1', 1, 20))    # Create object of Thread class
    t2 = multiprocessing.Process(target=task, args=('2', 1, 30))
    t1.start()                                                      # start the thread
    t2.start()
    for i in range(15):
    # for i in range(5):
        print('*', end='', flush=True)
        time.sleep(1)
    t1.join()
    t2.join()
    print('\nmain and threads done')

# ===================== data sharing : global var =====================

def demo2():

    result = []

    def taskSquare(request):
        nonlocal    result

        for item in request:
            result.append(item**2)
        print('result in taskSquare is:', result)


    # t1 = threading.Thread       (target=taskSquare, args=([1,2,3,4],))
    t1 = multiprocessing.Process(target=taskSquare, args=([1,2,3,4],))   
    t1.start()                                                      # start the thread
    t1.join()
    print('result in main is:', result)

# ================== data sharing : shared memory =====================
    
def demo3():

    def taskSquare(request, res_value, res_arr):
        res_value.value = sum(request)
        for idx, x in enumerate(request): res_arr[idx] = x*x


    v  = multiprocessing.Value('i')
    a  = multiprocessing.Array('i', 4)
    t1 = multiprocessing.Process(target=taskSquare, args=([1,2,3,4], v, a))   
    t1.start()
    t1.join()
    print('result in main is:', v.value, a[:])

# ================== data sharing : server process ====================
    
def demo4():

    def taskTriple(request, res):
        for x in request: res.append(x**3)
        

    with multiprocessing.Manager() as manager:
        result = manager.list([])
        t1 = multiprocessing.Process(target=taskTriple, args=([1,2,3,4], result))   
        t1.start()
        t1.join()
        print('result in main is:', result)

# ====================== data sharing : Queue =========================
    
def demo5():

    def taskSquare(request, q):
        for x in request: q.put(x*x)
        

    q  = multiprocessing.Queue()
    t1 = multiprocessing.Process(target=taskSquare, args=([1,2,3,4], q))   
    t1.start()
    t1.join()
    print('result in main is: ', end='')
    while not q.empty(): print(q.get(), end=(', '))
    print()

# ============================== Main =================================
            
demo1()
# demo2()
# demo3()
# demo4()
# demo5()

# =============================== End =================================
