By embedding, I think you may be referring to embedding Python in a C program 
with the Python C API.   That's not what I'm doing here -- I'm not using the 
Python C API.  The C program creates two threads (using pthreads), one for 
itself and one for the child process.  On creation, the second pthread is 
pointed to a C program that calls fork-execv to run the Python program.  That 
way Python runs on a separate thread.  The multiprocessing library "effectively 
side-step[s] the Global Interpreter Lock by using subprocesses instead of 
threads."  https://docs.python.org/3/library/multiprocessing.html.  This way I 
can get the Python functionality I want on call from the C program through 
pipes and shared memory.  

I don't want to use the C API because I will be making certain library calls 
from the C program, and the syntax is much easier with native Python code than 
with C API code. 

I hope that clarifies what I'm doing. 

Jen



Dec 5, 2021, 15:19 by ba...@barrys-emacs.org:

>
>
>
>
>> On 5 Dec 2021, at 17:54, Jen Kris <jenk...@tutanota.com> wrote:
>>
>>   
>> Thanks for your comments.  
>>
>> I put the Python program on its own pthread, and call a small C program to 
>> fork-execv to call the Python program as a child process. 
>>
>
> What do you mean by putting python in it’s own pthread?
> Are you embedding python in an other program?
>
> Barry
>
>
>
>> I revised the Python program to be a multiprocessing loop using the Python 
>> multiprocessing module.  That bypasses the GIL and allows Python to run 
>> concurrently with C.  So far so good.  
>>
>> Next I will use Linux pipes, not Python multiprocessing pipes, for IPC 
>> between Python and C.  Multiprocessing pipes are (as far as I can tell) only 
>> for commo between two Python processes.  I will have the parent thread send 
>> a signal through the pipe to the child process to exit when the parent 
>> thread is ready to exit, then call wait() to finalize the child process.  
>>
>> I will reply back when it's finished and post the code so you can see what I 
>> have done.  
>>
>> Thanks again.  
>>
>> Jen
>>
>>
>> Dec 4, 2021, 09:22 by ba...@barrys-emacs.org:
>>
>>>
>>>
>>>> On 1 Dec 2021, at 16:01, Jen Kris <>>>> jenk...@tutanota.com>>>> > wrote:
>>>>
>>>> Thanks for your comment re blocking.  
>>>>
>>>> I removed pipes from the Python and C programs to see if it blocks without 
>>>> them, and it does.
>>>>
>>>> It looks now like the problem is not pipes.
>>>>
>>>
>>> Ok.
>>>
>>>
>>>> I use fork() and execv() in C to run Python in a child process, but the 
>>>> Python process blocks
>>>>
>>>
>>> Use strace on the parent process to see what is happening.
>>> You will need to use the option to follow subprocesses so that you can see 
>>> what goes on in the python process.
>>>
>>> See man strace and the --follow-forks and --output-separately options.
>>> That will allow you to find the blocking system call that your code is 
>>> making.
>>>
>>>
>>>> because fork() does not create a new thread, so the Python global 
>>>> interpreter lock (GIL) prevents the C program from running once Python 
>>>> starts.
>>>>
>>>
>>> Not sure why you think this.
>>>
>>>
>>>>   So the solution appears to be run Python in a separate thread, which I 
>>>> can do with pthread create.
>>>>
>>>>   See "Thread State and the Global Interpreter Lock" >>>> 
>>>> https://docs.python.org/3/c-api/init.html#thread-state-and-the-global-interpreter-lock>>>>
>>>>   and the sections below that "Non-Python created threads" and "Cautions 
>>>> about fork()." 
>>>>
>>>
>>> I take it you mean that in the parent you think that using pthreads will 
>>> affect python after the exec() call?
>>> I does not. After exec() the process has one main thread create by the 
>>> kernel and a new address space as defined by the /usr/bin/python.
>>> The only state that in inherited from the parent are open file descriptors, 
>>> the current working directory and security state like UID, GID.
>>>
>>>
>>>> I'm working on that today and I hope all goes well :) 
>>>>
>>>
>>> You seem to be missing background information on how processes work.
>>> Maybe "Advanced Programming in the UNIX Environment" >>> would be helpful?
>>>
>>> https://www.amazon.co.uk/Programming-Environment-Addison-Wesley-Professional-Computing-dp-0321637739/dp/0321637739/ref=dp_ob_image_bk>>>
>>>   
>>>
>>> It's a great book and covers a wide range of Unix systems programming 
>>> topics.
>>>
>>> Have you created a small C program that just does the fork and exec of a 
>>> python program to test out your assumptions?
>>> If not I recommend that you do.
>>>
>>> Barry
>>>
>>>
>>>
>>>>
>>>>
>>>>
>>>> Nov 30, 2021, 11:42 by >>>> ba...@barrys-emacs.org>>>> :
>>>>
>>>>>
>>>>>
>>>>>
>>>>>> On 29 Nov 2021, at 22:31, Jen Kris <>>>>>> jenk...@tutanota.com>>>>>> > 
>>>>>> wrote:
>>>>>>
>>>>>> Thanks to you and Cameron for your replies.  The C side has an epoll_ctl 
>>>>>> set, but no event loop to handle it yet.  I'm putting that in now with a 
>>>>>> pipe write in Python-- as Cameron pointed out that is the likely source 
>>>>>> of blocking on C.  The pipes are opened as rdwr in Python because that's 
>>>>>> nonblocking by default.  The child will become more complex, but not in 
>>>>>> a way that affects polling.  And thanks for the tip about the c-string 
>>>>>> termination. 
>>>>>>
>>>>>>
>>>>>
>>>>> flags is a bit mask. You say its BLOCKing by not setting os.O_NONBLOCK.
>>>>> You should not use O_RDWR when you only need O_RDONLY access or only 
>>>>> O_WRONLY access.
>>>>>
>>>>> You may find
>>>>>
>>>>> man 2 open
>>>>>
>>>>> useful to understand in detail what is behind os.open().
>>>>>
>>>>> Barry
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>>
>>>>>>
>>>>>> Nov 29, 2021, 14:12 by >>>>>> ba...@barrys-emacs.org>>>>>> :
>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>> On 29 Nov 2021, at 20:36, Jen Kris via Python-list <>>>>>>>> 
>>>>>>>> python-list@python.org>>>>>>>> > wrote:
>>>>>>>>
>>>>>>>> I have a C program that forks to create a child process and uses 
>>>>>>>> execv to call a Python program.  The Python program communicates with 
>>>>>>>> the parent process (in C) through a FIFO pipe monitored with epoll(). 
>>>>>>>>
>>>>>>>> The Python child process is in a while True loop, which is intended to 
>>>>>>>> keep it running while the parent process proceeds, and perform 
>>>>>>>> functions for the C program only at intervals when the parent sends 
>>>>>>>> data to the child -- similar to a daemon process. 
>>>>>>>>
>>>>>>>> The C process writes to its end of the pipe and the child process 
>>>>>>>> reads it, but then the child process continues to loop, thereby 
>>>>>>>> blocking the parent. 
>>>>>>>>
>>>>>>>> This is the Python code:
>>>>>>>>
>>>>>>>> #!/usr/bin/python3
>>>>>>>> import os
>>>>>>>> import select
>>>>>>>>
>>>>>>>> #Open the named pipes
>>>>>>>> pr = os.open('/tmp/Pipe_01', os.O_RDWR)
>>>>>>>>
>>>>>>> Why open rdwr if you are only going to read the pipe?
>>>>>>>
>>>>>>>> pw = os.open('/tmp/Pipe_02', os.O_RDWR)
>>>>>>>>
>>>>>>> Only need to open for write.
>>>>>>>
>>>>>>>>
>>>>>>>> ep = select.epoll(-1)
>>>>>>>> ep.register(pr, select.EPOLLIN)
>>>>>>>>
>>>>>>>
>>>>>>> Is the only thing that the child does this:
>>>>>>> 1. Read message from pr
>>>>>>> 2. Process message
>>>>>>> 3. Write result to pw.
>>>>>>> 4. Loop from 1
>>>>>>>
>>>>>>> If so as Cameron said you do not need to worry about the poll.
>>>>>>> Do you plan for the child to become more complex?
>>>>>>>
>>>>>>>>
>>>>>>>> while True:
>>>>>>>>
>>>>>>>> events = ep.poll(timeout=2.5, maxevents=-1)
>>>>>>>> #events = ep.poll(timeout=None, maxevents=-1)
>>>>>>>>
>>>>>>>> print("child is looping")
>>>>>>>>
>>>>>>>> for fileno, event in events:
>>>>>>>> print("Python fileno")
>>>>>>>> print(fileno)
>>>>>>>> print("Python event")
>>>>>>>> print(event)
>>>>>>>> v = os.read(pr,64)
>>>>>>>> print("Pipe value")
>>>>>>>> print(v)
>>>>>>>>
>>>>>>>> The child process correctly receives the signal from ep.poll and 
>>>>>>>> correctly reads the data in the pipe, but then it continues looping.  
>>>>>>>> For example, when I put in a timeout:
>>>>>>>>
>>>>>>>> child is looping
>>>>>>>> Python fileno
>>>>>>>> 4
>>>>>>>> Python event
>>>>>>>> 1
>>>>>>>> Pipe value
>>>>>>>> b'10\x00'
>>>>>>>>
>>>>>>> The C code does not need to write a 0 bytes at the end.
>>>>>>> I assume the 0 is from the end of a C string.
>>>>>>> UDS messages have a length.
>>>>>>> In the C just write 2 byes in the case.
>>>>>>>
>>>>>>> Barry
>>>>>>>
>>>>>>>> child is looping
>>>>>>>> child is looping
>>>>>>>>
>>>>>>>> That suggests that a while True loop is not the right thing to do in 
>>>>>>>> this case.  My question is, what type of process loop is best for this 
>>>>>>>> situation?  The multiprocessing, asyncio and subprocess libraries are 
>>>>>>>> very extensive, and it would help if someone could suggest the best 
>>>>>>>> alternative for what I am doing here. 
>>>>>>>>
>>>>>>>> Thanks very much for any ideas. 
>>>>>>>>
>>>>>>>>
>>>>>>>> -- 
>>>>>>>> https://mail.python.org/mailman/listinfo/python-list
>>>>>>>>
>>>>>>
>>>>>>
>>>>
>>>>
>>
>>

-- 
https://mail.python.org/mailman/listinfo/python-list

Reply via email to