On 04-May-2019 20:31, Liu Hao wrote:
在 2019/5/4 上午6:16, David Mathog 写道:
Thanks for the feedback, but I'm still nowhere near getting this to
work.
Issues:
1. Compiler warnings:
c_spawn_n.c: In function 'main':
c_spawn_n.c:47:13: warning: passing argument 3 of 'CreateThread' from
incompatible pointer type [-Wincompatible-pointer-types]
RunCommand, // thread function name
^~~~~~~~~~
`LPTHREAD_START_ROUTINE` is the type of the parameter of
`CreateThread()`, which a pointer-to-function. The proper return type
for a thread procedure is `DWORD` rather than this thing.
Changed the called routine to (see below):
DWORD RunCommand( void *lpParam ){
but ...
gcc -g -O0 -o c_spawn_n c_spawn_n.c
c_spawn_n.c: In function 'main':
c_spawn_n.c:47:13: warning: passing argument 3 of 'CreateThread' from
incompatible pointer type [-Wincompatible-pointer-types]
RunCommand, // thread function name
^~~~~~~~~~
In file included from
C:/progs/msys32/mingw32/i686-w64-mingw32/include/winbase.h:29:0,
from
C:/progs/msys32/mingw32/i686-w64-mingw32/include/windows.h:70,
from c_spawn_n.c:7:
C:/progs/msys32/mingw32/i686-w64-mingw32/include/processthreadsapi.h:163:28:
note: expected 'LPTHREAD_START_ROUTINE' but argument is of type 'DWORD
(*)(void *) {aka long unsigned int (*)(void *)}'
WINBASEAPI HANDLE WINAPI CreateThread (LPSECURITY_ATTRIBUTES
lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE
lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD
lpThreadId);
^~~~~~~~~~~~
The processthreadsapi.h header line does indeed contain the type which
the compiler
is warning about:
grep CreateThread
C:/progs/msys32/mingw32/i686-w64-mingw32/include/processthreadsapi.h
WINBASEAPI HANDLE WINAPI CreateThread (LPSECURITY_ATTRIBUTES
lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE
lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD
lpThreadId);
I don't see how to reconcile this.
2. when run procs is shown as -1, not sure how that happens.
Use `WaitForSingleObject()` to await **every** thread in a loop. Do not
use `WaitForMultipleObjects()` as it has a upper limit of number of
handles to wait for, and the return value is hard to handle properly
(as
you already did that wrong).
You lost me. WaitForSingleObject() will only wait on a single handle at
a time. There might
be 20 subprocesses running, each with its own handle. A function is
needed which will return
when the first of those exits. Would that not be
WaitForMultipleObjects()? Even if it will
only work for lets say the first 16 processes, hopefully once those exit
the invisible ones
would slide into view? Or maybe it doesn't work that way?
Don't forget to `CloseHandle()` when a thread handle is out of
interest.
The POSIX function `wait()` waits for a child process and frees its
resource, but on Windows you close its handle explicitly; wait
functions
do not free resources of it.
OK, added that. For good measure set the handle pointer to NULL after
closing it.
3. cannot tell very well if this is actually starting multiple
processes or if it
is just running sequentially.
4. there are now about about 100 cmd.exe processes showing up in
Windows Task Manager.
The `system` function passes its argument to the program designated by
the environment variable `COMSPEC` (which seems to have to be an
absolute path), which by default is `CMD.EXE` so you get a number of
instances.
If this is unacceptable you have to spawn child processes using
`CreateProcess()` and redirect standard streams yourself. There is a
nice document about this [1].
[1]
https://docs.microsoft.com/en-us/windows/desktop/ProcThread/creating-a-child-process-with-redirected-input-and-output
So something is hanging somewhere. It was run both in "MSYS2 Mingw
32"
and a W7
cmd shell. These processes are not visible in "ps -ef" in the
former.
`ps` only shows programs that run on the abstraction layer for POSIX of
MSYS2; native programs are out of its management.
5. Pretty sure I'm not checking status right on the thread creation
and
not
passing the system() exit status back correctly (or at all).
6. During the test it says this a variable number of times:
The process cannot access the file because it is being used by
another
process.
Rewrote the example. The input file was simplified to commands3.txt and
is now:
dir #c_spawn_n.c# > #c_spawn_n.c#.killme
dir accudate.1 > accudate.1.killme
dir accudate.c > accudate.c.killme
(which should run in either shell, those were just 3 files which were
available
in the current directory.)
Rewrote the code to NOT check for running processes until all (3) were
started.
Ran it like:
./c_spawn_n <commands3.txt
DEBUG firstempty 0 command >dir #c_spawn_n.c# > #c_spawn_n.c#.killme<
len 40 procs 0
DEBUG firstempty 1 command >dir accudate.1 > accudate.1.killme< len 34
procs 1
DEBUG firstempty 2 command >dir accudate.c > accudate.c.killme< len 34
procs 2
DEBUG CLEANUP thread -1 exited with status 4200656l
DEBUG CLEANUP thread -1 exited with status 4200656l
DEBUG CLEANUP thread -1 exited with status 4200656l
It is checking for a returned NULL handle, and that isn't happening, so
the threads
seemed to have started.
SOMETIMES it makes one or more killme files, sometimes it does not.
The commands are independent of each other, so unclear how they might
be interfering in this case.
Sometimes cmd.exe are left running as seen in the task manager.
Sometimes not.
Tried various values for the return status from RunCommand, among them 0
and 10.
Didn't seem to make any difference.
Again, this is in a mingw32 shell, using that gcc. Current code:
// c_spawn_n.c
// TEST program to run up to 20 commands in parallel as subprocesses.
// Read commands from stdin.
//
//
#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <process.h>
#include <unistd.h>
// prototypes
DWORD WINAPI RunCommand( void *lpParam ); // runs thread
int max_threads=20;
int procs=0; // Number of processes running
int main(int argc, char *argv[]){
#define MAXSTRING 256
char *command = malloc(MAXSTRING);
char **ThrCommands = calloc(sizeof(char *), max_threads);
HANDLE *ThrHandles = (HANDLE *) calloc(sizeof(HANDLE),max_threads);
DWORD *ThreadIds = (DWORD *) calloc(sizeof(DWORD),max_threads);
int firstempty=0;
int procs=0;
DWORD retVal;
while(1){
if(NULL == fgets(command,MAXSTRING,stdin))break;
//DEBUG simple test, just run 3 commands in order before checking for
exit
if(0 && procs > 0){
firstempty = WaitForMultipleObjects(
max_threads, ThrHandles, FALSE, INFINITE);
procs--;
GetExitCodeThread(ThrHandles[firstempty], &retVal);
CloseHandle(ThrHandles[firstempty]);
free(ThrCommands[firstempty]);
ThrCommands[firstempty]=NULL;
fprintf(stderr,"DEBUG thread %d exited with status %ul\n",
firstempty,retVal);
}
//remove final character
int clen=strlen(command);
if(clen<=1)break; // exit on an empty line
command[strlen(command)-1]='\0';
fprintf(stderr,"DEBUG firstempty %d command >%s< len %d procs %d\n",
firstempty,command,strlen(command),procs);
ThrCommands[firstempty] = strdup(command); // save it
ThrHandles[firstempty] = CreateThread(
NULL, // default security attributes
0, // use default stack size
RunCommand, // thread function name
ThrCommands[firstempty],// argument to thread function
0, // use default creation flags
&ThreadIds[firstempty]); // returns the thread identifier
if(ThrHandles[firstempty] == NULL){
fprintf(stderr,"DEBUG CreateThread failed\n");
}
procs++;
firstempty++; //DEBUG
}
// wait for threads to exit
while(procs>0){
firstempty = WaitForMultipleObjects(
max_threads, ThrHandles, FALSE, INFINITE);
procs--;
GetExitCodeThread(ThrHandles[firstempty], &retVal);
CloseHandle(ThrHandles[firstempty]);
free(ThrCommands[firstempty]);
ThrCommands[firstempty]=NULL;
fprintf(stderr,"DEBUG CLEANUP thread %d exited with status %ul\n",
firstempty,retVal);
}
}
// run a command, return its exit status
DWORD WINAPI RunCommand( void *lpParam ){
char *command = (char *) lpParam;
int retval = system(command);
// output from next command never appears in console (DOS or MSYS)
//fprintf(stderr,"DEBUG RunCommand status %d with command
%s\n",retval,command);
return (0); //DEBUG
// return (retval);
}
Thanks,
David Mathog
mat...@caltech.edu
Manager, Sequence Analysis Facility, Biology Division, Caltech
_______________________________________________
Mingw-w64-public mailing list
Mingw-w64-public@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/mingw-w64-public