Vlc library fails when I use fork() in C and Ubuntu - c

I can't understand why I keep to get this error:
ALSA lib pcm_dmix.c:1108:(snd_pcm_dmix_open) unable to open slave
[00005617d3cf0630] alsa audio output error: cannot open ALSA device "default": No such file or directory
[00005617d3cf0630] main audio output error: Audio output failed
[00005617d3cf0630] main audio output error: The audio device "default" could not be used:
No such file or directory.
[00005617d3cf0630] main audio output error: module not functional
[00007f2ce803b080] main decoder error: failed to create audio output
when I try to reproduce a mp3 file with a fork().
The code works pretty fine if I use it outside the fork().
It looks like the child process can't access the hardware sound card?
I really can't understand how can I solve the problem.
pid = fork();
printf("il pid: %d\n", pid);
if (pid == 0) {
libvlc_instance_t *inst;
libvlc_media_player_t *mp;
libvlc_media_t *m;
// load the vlc engine
inst = libvlc_new(0, NULL);
printf("apro il file \n");
// create a new item
m = libvlc_media_new_path(inst, "/home/robodyne/Downloads/file.mp3");
// create a media play playing environment
mp = libvlc_media_player_new_from_media(m);
// no need to keep the media now
libvlc_media_release(m);
// play the media_player
libvlc_media_player_play(mp);
sleep(10);
// stop playing
libvlc_media_player_stop(mp);
// free the media_player
libvlc_media_player_release(mp);
libvlc_release(inst);
exit(0);
}
EDIT1: I'm trying to use THREADS
Following the suggestion of Antti Haapala, I tried to use threads instead of fork() but when I call "pthread_cancel(thread);", the mp3 doesn't stop.
This is my new code:
pthread_t thread;
void *wait(void*)
{
libvlc_instance_t *inst;
libvlc_media_player_t *mp;
libvlc_media_t *m;
// load the vlc engine
inst = libvlc_new(0, NULL);
printf("apro il file %d\n", inst);
// create a new item
m = libvlc_media_new_path(inst, "/home/robodyne/Downloads/file.mp3");
// create a media play playing environment
mp = libvlc_media_player_new_from_media(m);
// no need to keep the media now
libvlc_media_release(m);
// play the media_player
libvlc_media_player_play(mp);
sleep(10);
// stop playing
libvlc_media_player_stop(mp);
// free the media_player
libvlc_media_player_release(mp);
libvlc_release(inst);
printf("Done.\n");
}
SecondPage::SecondPage(wxWindow* parent,wxWindowID id)
{
//(*Initialize(SecondPage)
Create(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE, _T("wxID_ANY"));
SetClientSize(wxSize(1314,769));
SetBackgroundColour(wxColour(175,253,202));
// some code from wxwidgets removed
m_reboot.Bind(wxEVT_TIMER, &SecondPage::Reboot, this);
if (get_day_of_year() == 2 || get_day_of_year() == 4){
secco->Show();
}
pthread_create(&thread, NULL, wait, NULL);
}
void SecondPage::OnplasticaClick(wxCommandEvent& event)
{
pthread_cancel(thread);
thirdpage = new ThirdPage(nullptr, 2);
thirdpage->selezione="plastica";
strcpy(thirdpage->codice_fiscale, codice_fiscale);
thirdpage->tipologia_rifiuto->SetLabel(thirdpage->selezione);
thirdpage->Refresh();
thirdpage->Update();
thirdpage->m_reboot.StartOnce(600000);
thirdpage->Show(true);
this->Hide();
}

A fork is never safe in a multi-threaded program, except when immediately followed by exit or exec. It is not clear what you do before calling fork but you do something non-trivial for sure, otherwise there would not be any difference between this forked version and the one that does not fork.
Unfortunately there are really 3 alternatives:
fork really early in the program execution, before any libraries are used,
use threads
execute another program - for example the same executable with different arguments so that it knows it is the child in the forked process.

I think this problem is most likely solved in newer versions like pulseaudio.
Let's define the problem. If you open alsa and then create a fork, allocated resources of alsa shared both by parent and child. This is the big problem for dmix. To avoid this problem, you should either have a separate application where you will do the sound issues, or you should not fork without closing alsa.

Related

SetWindowsHookEx injection failed on release mode but worked on debug mode

I'm writing a program which monitors Keystrokes of a target process using SetWindowsHookEx. (IDE: Visual Studio 2013)Here's an overview of my program:
Obtain a HWND of the target process using FindWindow().
If HWND is valid, obtain the process id using GetWindowThreadProcessId()
Obtain a thread id by traversing the thread list with CreateToolhelp32Snapshot(TH32CS_THREAD)
Call SetWindowsHookEx().
Actual code:
//obtain the window handle
HWND hwnd = FindWindowA(NULL, "A valid title");
DWORD pid = 0;
//obtain the process id.
GetWindowThreadProcessId(hwnd, &pid);
//obtain the thread id.
DWORD threadId = GetThreadId(pid);
printf("Injecting to Process: %d Thread: %d\n", pid, threadId);
HMODULE hDll = LoadLibraryA("TestDLL.dll");
if (hDll == INVALID_HANDLE_VALUE)
{
printf("LoadLibrary() failed! %d!\n", GetLastError());
return 0;
}
HOOKPROC hookproc = (HOOKPROC)GetProcAddress(hDll, "KeyboardProc");
if (!hookproc)
{
printf("GetProcAddress() failed\n");
return 0;
}
HHOOK hook = SetWindowsHookEx(WH_CALLWNDPROC, hookproc, hDll, threadId);
if (!hook)
{
printf("SetWindowsHookEx() failed! %d\n", GetLastError());
return 0;
}
//post a message. This will trigger the hook and cause the target process
//to load my dll. Actual key monitoring code is inside the dll.
printf("SendMessage() returns:%d", SendMessage(hwnd, WM_NULL, 0, 0));
printf("Success!\n");
UnhookWindowsHookEx(hook);
getchar();
Under Debug mode, the output shows:
Injecting to process 4052 Thread:460
SendMessage() returns:0
Success!
A simple analysis shows that the target process did load my dll. Which means the program works. However, under release mode, the output is the same but dll is not loaded into the target process. I tried this multiple times with restarting target process each time. But still doesn't work.
How do I resolve this problem?
When you say "under Debug mode" - does it mean that you are debugging inside VS?
If so, my guess that the problem might be in permission set - you can run VS with elevated permissions or under another user/group. Try to run your release version of the app in Admin mode. Otherwise it would be a security flaw if any process can inject code into any another process.

waitpid() for non-child processes [duplicate]

For child processes, the wait() and waitpid() functions can be used to suspends execution of the current process until a child has exited. But this function can not be used for non-child processes.
Is there another function, which can wait for exit of any process ?
Nothing equivalent to wait(). The usual practice is to poll using kill(pid, 0) and looking for return value -1 and errno of ESRCH to indicate that the process is gone.
Update: Since linux kernel 5.3 there is a pidfd_open syscall, which creates an fd for a given pid, which can be polled to get notification when pid has exited.
On BSDs and OS X, you can use kqueue with EVFILT_PROC+NOTE_EXIT to do exactly that. No polling required. Unfortunately there's no Linux equivalent.
So far I've found three ways to do this on Linux:
Polling: you check for the existence of the process every so often, either by using kill or by testing for the existence of /proc/$pid, as in most of the other answers
Use the ptrace system call to attach to the process like a debugger so you get notified when it exits, as in a3nm's answer
Use the netlink interface to listen for PROC_EVENT_EXIT messages - this way the kernel tells your program every time a process exits and you just wait for the right process ID. I've only seen this described in one place on the internet.
Shameless plug: I'm working on a program (open source of course; GPLv2) that does any of the three.
You could also create a socket or a FIFO and read on them. The FIFO is especially simple: Connect the standard output of your child with the FIFO and read. The read will block until the child exits (for any reason) or until it emits some data. So you'll need a little loop to discard the unwanted text data.
If you have access to the source of the child, open the FIFO for writing when it starts and then simply forget about it. The OS will clean the open file descriptor when the child terminates and your waiting "parent" process will wake up.
Now this might be a process which you didn't start or own. In that case, you can replace the binary executable with a script that starts the real binary but also adds monitoring as explained above.
Here is a way to wait for any process (not necessarily a child) in linux to exit (or get killed) without polling:
Using inotify to wait for the /proc'pid' to be deleted would be the perfect solution, but unfortunately inotify does not work with pseudo file systems like /proc.
However we can use it with the executable file of the process.
While the process still exists, this file is being held open.
So we can use inotify with IN_CLOSE_NOWRITE to block until the file is closed.
Of course it can be closed for other reasons (e.g. if another process with the same executable exits) so we have to filter those events by other means.
We can use kill(pid, 0), but that can't guarantee if it is still the same process. If we are really paranoid about this, we can do something else.
Here is a way that should be 100% safe against pid-reuse trouble: we open the pseudo directory /proc/'pid', and keep it open until we are done. If a new process is created in the meantime with the same pid, the directory file descriptor that we hold will still refer to the original one (or become invalid, if the old process cease to exist), but will NEVER refer the new process with the reused pid. Then we can check if the original process still exists by checking, for example, if the file "cmdline" exists in the directory with openat(). When a process exits or is killed, those pseudo files cease to exist too, so openat() will fail.
here is an example code:
// return -1 on error, or 0 if everything went well
int wait_for_pid(int pid)
{
char path[32];
int in_fd = inotify_init();
sprintf(path, "/proc/%i/exe", pid);
if (inotify_add_watch(in_fd, path, IN_CLOSE_NOWRITE) < 0) {
close(in_fd);
return -1;
}
sprintf(path, "/proc/%i", pid);
int dir_fd = open(path, 0);
if (dir_fd < 0) {
close(in_fd);
return -1;
}
int res = 0;
while (1) {
struct inotify_event event;
if (read(in_fd, &event, sizeof(event)) < 0) {
res = -1;
break;
}
int f = openat(dir_fd, "fd", 0);
if (f < 0) break;
close(f);
}
close(dir_fd);
close(in_fd);
return res;
}
You could attach to the process with ptrace(2). From the shell, strace -p PID >/dev/null 2>&1 seems to work. This avoid the busy-waiting, though it will slow down the traced process, and will not work on all processes (only yours, which is a bit better than only child processes).
None I am aware of. Apart from the solution from chaos, you can use semaphores if you can change the program you want to wait for.
The library functions are sem_open(3), sem_init(3), sem_wait(3), ...
sem_wait(3) performs a wait, so you don´t have to do busy waiting as in chaos´ solution. Of course, using semaphores makes your programs more complex and it may not be worth the trouble.
Maybe it could be possible to wait for /proc/[pid] or /proc/[pid]/[something] to disappear?
There are poll() and other file event waiting functions, maybe that could help?
Since linux kernel 5.3 there is a pidfd_open syscall, which creates an fd for a given pid, which can be polled to get notification when pid has exited.
Simply poll values number 22 and 2 of the /proc/[PID]/stat.
The value 2 contains name of the executable and 22 contains start time.
If they change, some other process has taken the same (freed) PID. Thus the method is very reliable.
You can use eBPF to achieve this.
The bcc toolkit implements many excellent monitoring capabilities based on eBPF. Among them, exitsnoop traces process termination, showing the command name and reason for termination,
either an exit or a fatal signal.
It catches processes of all users, processes in containers, as well as processes that
become zombie.
This works by tracing the kernel sched_process_exit() function using dynamic tracing, and
will need updating to match any changes to this function.
Since this uses BPF, only the root user can use this tool.
You can refer to this tool for related implementation.
You can get more information about this tool from the link below:
Github repo: tools/exitsnoop: Trace process termination (exit and fatal signals). Examples.
Linux Extended BPF (eBPF) Tracing Tools
ubuntu manpages: exitsnoop-bpfcc
You can first install this tool and use it to see if it meets your needs, and then refer to its implementation for coding, or use some of the libraries it provides to implement your own functions.
exitsnoop examples:
Trace all process termination
# exitsnoop
Trace all process termination, and include timestamps:
# exitsnoop -t
Exclude successful exits, only include non-zero exit codes and fatal signals:
# exitsnoop -x
Trace PID 181 only:
# exitsnoop -p 181
Label each output line with 'EXIT':
# exitsnoop --label EXIT
Another option
Wait for a (non-child) process' exit using Linux's PROC_EVENTS
Reference project:
https://github.com/stormc/waitforpid
mentioned in the project:
Wait for a (non-child) process' exit using Linux's PROC_EVENTS. Thanks
to the CAP_NET_ADMIN POSIX capability permitted to the waitforpid
binary, it does not need to be set suid root. You need a Linux kernel
having CONFIG_PROC_EVENTS enabled.
Appricate #Hongli's answer for macOS with kqueue. I implement it with swift
/// Wait any pids, including non-child pid. Block until all pids exit.
/// - Parameters:
/// - timeout: wait until interval, nil means no timeout
/// - Throws: WaitOtherPidError
/// - Returns: isTimeout
func waitOtherPids(_ pids: [Int32], timeout: TimeInterval? = nil) throws -> Bool {
// create a kqueue
let kq = kqueue()
if kq == -1 {
throw WaitOtherPidError.createKqueueFailed(String(cString: strerror(errno)!))
}
// input
// multiple changes is OR relation, kevent will return if any is match
var changes: [Darwin.kevent] = pids.map({ pid in
Darwin.kevent.init(ident: UInt(pid), filter: Int16(EVFILT_PROC), flags: UInt16(EV_ADD | EV_ENABLE), fflags: NOTE_EXIT, data: 0, udata: nil)
})
let timeoutDeadline = timeout.map({ Date(timeIntervalSinceNow: $0)})
let remainTimeout: () ->timespec? = {
if let deadline = timeoutDeadline {
let d = max(deadline.timeIntervalSinceNow, 0)
let fractionalPart = d - TimeInterval(Int(d))
return timespec(tv_sec: Int(d), tv_nsec: Int(fractionalPart * 1000 * 1000 * 1000))
} else {
return nil
}
}
// output
var events = changes.map{ _ in Darwin.kevent.init() }
while !changes.isEmpty {
// watch changes
// sync method
let numOfEvent: Int32
if var timeout = remainTimeout() {
numOfEvent = kevent(kq, changes, Int32(changes.count), &events, Int32(events.count), &timeout);
} else {
numOfEvent = kevent(kq, changes, Int32(changes.count), &events, Int32(events.count), nil);
}
if numOfEvent < 0 {
throw WaitOtherPidError.keventFailed(String(cString: strerror(errno)!))
}
if numOfEvent == 0 {
// timeout. Return directly.
return true
}
// handle the result
let realEvents = events[0..<Int(numOfEvent)]
let handledPids = Set(realEvents.map({ $0.ident }))
changes = changes.filter({ c in
!handledPids.contains(c.ident)
})
for event in realEvents {
if Int32(event.flags) & EV_ERROR > 0 { // #see 'man kevent'
let errorCode = event.data
if errorCode == ESRCH {
// "The specified process to attach to does not exist"
// ingored
} else {
print("[Error] kevent result failed with code \(errorCode), pid \(event.ident)")
}
} else {
// succeeded event, pid exit
}
}
}
return false
}
enum WaitOtherPidError: Error {
case createKqueueFailed(String)
case keventFailed(String)
}
PR_SET_PDEATHSIG can be used to wait for parent process termination

Run process and wait for it AND its child processes to end [duplicate]

Is it possible to wait for all processes launched by a child process in Windows? I can't modify the child or grandchild processes.
Specifically, here's what I want to do. My process launches uninstallA.exe. The process uninistallA.exe launches uninstallB.exe and immediately exits, and uninstallB.exe runs for a while. I'd like to wait for uninstallB.exe to exit so that I can know when the uninstall is finished.
Create a Job Object with CreateJobObject. Use CreateProcess to start UninstallA.exe in a suspended state. Assign that new process to your job object with AssignProcessToJobObject. Start UninstallA.exe running by calling ResumeThread on the handle of the thread you got back from CreateProcess.
Then the hard part: wait for the job object to complete its execution. Unfortunately, this is quite a bit more complex than anybody would reasonably hope for. The basic idea is that you create an I/O completion port, then you create the object object, associate it with the I/O completion port, and finally wait on the I/O completion port (getting its status with GetQueuedCompletionStatus). Raymond Chen has a demonstration (and explanation of how this came about) on his blog.
Here's a technique that, while not infallible, can be useful if for some reason you can't use a job object. The idea is to create an anonymous pipe and let the child process inherit the handle to the write end of the pipe.
Typically, grandchild processes will also inherit the write end of the pipe. In particular, processes launched by cmd.exe (e.g., from a batch file) will inherit handles.
Once the child process has exited, the parent process closes its handle to the write end of the pipe, and then attempts to read from the pipe. Since nobody is writing to the pipe, the read operation will block indefinitely. (Of course you can use threads or asynchronous I/O if you want to keep doing stuff while waiting for the grandchildren.)
When (and only when) the last handle to the write end of the pipe is closed, the write end of the pipe is automatically destroyed. This breaks the pipe and the read operation completes and reports an ERROR_BROKEN_PIPE failure.
I've been using this code (and earlier versions of the same code) in production for a number of years.
// pwatch.c
//
// Written in 2011 by Harry Johnston, University of Waikato, New Zealand.
// This code has been placed in the public domain. It may be freely
// used, modified, and distributed. However it is provided with no
// warranty, either express or implied.
//
// Launches a process with an inherited pipe handle,
// and doesn't exit until (a) the process has exited
// and (b) all instances of the pipe handle have been closed.
//
// This effectively waits for any child processes to exit,
// PROVIDED the child processes were created with handle
// inheritance enabled. This is usually but not always
// true.
//
// In particular if you launch a command shell (cmd.exe)
// any commands launched from that command shell will be
// waited on.
#include <windows.h>
#include <stdio.h>
void error(const wchar_t * message, DWORD err) {
wchar_t msg[512];
swprintf_s(msg, sizeof(msg)/sizeof(*msg), message, err);
printf("pwatch: %ws\n", msg);
MessageBox(NULL, msg, L"Error in pwatch utility", MB_OK | MB_ICONEXCLAMATION | MB_SYSTEMMODAL);
ExitProcess(err);
}
int main(int argc, char ** argv) {
LPWSTR lpCmdLine = GetCommandLine();
wchar_t ch;
DWORD dw, returncode;
HANDLE piperead, pipewrite;
STARTUPINFO si;
PROCESS_INFORMATION pi;
SECURITY_ATTRIBUTES sa;
char buffer[1];
while (ch = *(lpCmdLine++)) {
if (ch == '"') while (ch = *(lpCmdLine++)) if (ch == '"') break;
if (ch == ' ') break;
}
while (*lpCmdLine == ' ') lpCmdLine++;
sa.nLength = sizeof(sa);
sa.bInheritHandle = TRUE;
sa.lpSecurityDescriptor = NULL;
if (!CreatePipe(&piperead, &pipewrite, &sa, 1)) error(L"Unable to create pipes: %u", GetLastError());
GetStartupInfo(&si);
if (!CreateProcess(NULL, lpCmdLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
error(L"Error %u creating process.", GetLastError());
if (WaitForSingleObject(pi.hProcess, INFINITE) == WAIT_FAILED) error(L"Error %u waiting for process.", GetLastError());
if (!GetExitCodeProcess(pi.hProcess, &returncode)) error(L"Error %u getting exit code.", GetLastError());
CloseHandle(pipewrite);
if (ReadFile(piperead, buffer, 1, &dw, NULL)) {
error(L"Unexpected data received from pipe; bug in application being watched?", ERROR_INVALID_HANDLE);
}
dw = GetLastError();
if (dw != ERROR_BROKEN_PIPE) error(L"Unexpected error %u reading from pipe.", dw);
return returncode;
}
There is not a generic way to wait for all grandchildren but for your specific case you may be able to hack something together. You know you are looking for a specific process instance. I would first wait for uninstallA.exe to exit (using WaitForSingleObject) because at that point you know that uninstallB.exe has been started. Then use EnumProcesses and GetProcessImageFileName from PSAPI to find the running uninstallB.exe instance. If you don't find it you know it has already finished, otherwise you can wait for it.
An additional complication is that if you need to support versions of Windows older than XP you can't use GetProcessImageFileName, and for Windows NT you can't use PSAPI at all. For Windows 2000 you can use GetModuleFileNameEx but it has some caveats that mean it might fail sometimes (check docs). If you have to support NT then look up Toolhelp32.
Yes this is super ugly.
Use a named mutex.
One possibility is to install Cygwin and then use the ps command to watch for the grandchild to exit

Unable to code with threading as an alternative to fork()

I am coding on Windows, so fork() is not available. Now, i need to run execl(), but it is an end point of my program! I thought of creating a separate thread to run execl(), which is created successfully, and runs well also. But still my program comes to an end after thread is over.
Function running thread--It is inside class wScoreget:-
int refresh_score_now(){
pthread_t t;
if(pthread_create(&t,NULL,s.basicgetscore,&s)==-1){
printf("Error: wScoreget:3");
exit(4);
}
void *a;
if(pthread_join(t,&a)==-1){
printf("Error: wScoreget: 4");
exit(4);
printf("Running thread.\n");
getch();
}
}
Calling from main:-
int main(){
wScoreget new_ws;
new_ws.refresh_score_now();
printf("reached to the end\n");
getch();
}
I am expecting console to print- "reached to the end"
But on execl() it exits.
NOTE: execl() is running curl. Its output is going to a text file. Now, if stdout is changed, curl shows download timing and other data on the console. THAT data comes to console anyways.
Is there a way I can do this without using CreateProcess? And if I use CreateProcess, which libraries do I have to install on Windows(I am using MingW + Codeblocks).
Try using spawn or posix_spawn. It should replace fork + exec.
http://en.wikipedia.org/wiki/Spawn_%28computing%29
http://linux.die.net/man/3/posix_spawn

sending same data to multiple threads over pipes?

I have a ressource manager that handles multiple TCP-Connections. These connections are pthreads. How can I manage it to send data from the Ressource Manager to all of these threads? Or even better: How can I figure out to which thread I have to send this command?
For example: I have 2 Threads, one with pid 3333, one with pid 4444. The user sends a task to program a board (it is a ressource manager that manages FPGA-boards). The ressource manager picks a board from a list, where also this pid is saved. Then the program-command should be send to the thread with this pid or, what I was thinking in the first place, to all of the threads and the threads decide if they go on or not. Protocol looks like this: <pid>#<board-id>#<file>
I open 2 pipes (for writing to the threads and reading from the threads) in the main.c and give them as an argument to the listening-thread (forthread-struct).
main.c
// open Pipes to SSL
int rmsslpipe[2];
int sslrmpipe[2];
if (pipe(rmsslpipe) == -1) {
writelog(LOGERROR, "main: could not create RM-SSL reading pipe");
exit(1);
}
if (pipe(sslrmpipe) == -1) {
writelog(LOGERROR, "main: could not create RM-SSL reading pipe");
exit(1);
}
int rmtosslserver = rmsslpipe[1];
int sslservertorm = sslrmpipe[0];
// start SSL-Server as a pthread
pthread_t thread;
forthread* ft = malloc(sizeof(forthread));
ft->rmtosslserver = rmsslpipe[0];
ft->sslservertorm = sslrmpipe[1];
pthread_mutex_t ftmutex;
pthread_mutex_init(&ftmutex, NULL);
ft->mutex = ftmutex;
pthread_create(&thread, NULL, startProgramserver, (void*) ft);
This thread now listens for new connections and if there is a new connection, it creates a new thread with the forthread-struct as argument. This thread is where the action happens :)
void* startProgramserver(void* ft) {
int sock, s;
forthread* f = (forthread*) ft;
// open TCP-Socket
sock = tcp_listen();
while(1){
if((s=accept(sock,0,0))<0) {
printf("Problem accepting");
// try again
sleep(60);
continue;
}
writelog(LOGNOTE, "New SSL-Connection accepted");
f->socket = s;
pthread_t thread;
pthread_create(&thread, NULL, serveClient, (void*) f);
}
exit(0);
}
This thread now initializes the connection, gets some information from the client and then waits for the ressource manager to get new commands.
n=read(f->rmtosslserver, bufw, BUFSIZZ);
But this fails if there is more than only one thread. So how can I manage that?
If you have one thread per board, the "pid" shouldn't be needed in the command -- you just need a way to find the right thread (or queue, or whatever) for the specified board.
You could keep a list of your forthread structures, and include the board ID in the structure. Also include a way of passing commands; this could be a pipe, but you may as well use some sort of queue or list instead. That way you use one pipe (or other mechanism) per thread instead of a single shared one, and can find the right one for each board by searching the forthread list for the one with the right board ID. Just be sure to protect any parts of the structure that may be modified while the thread runs with a mutex.
The problem with using a single pipe as you've suggested is that only one thread will get each command -- if it's the wrong one, too bad; the command is gone.
The answer is Yes. I would use a list of them.However I can open a pipe more than 1 when the the speed of the PC is very slow. 2 connections for 2 connections.

Resources