cambios2.cpp
, cuya adecuada compilación producirá
el ejecutable cambios2.exe
. Se trata de realizar
una práctica casi idéntica a la segunda
práctica de este año, pero
mediante un programa que realice llamadas a la API de WIN32.
libcambios.a
. La biblioteca se llamará
cambios2.dll
.
cambios2.exe
). Se podrán usar argumentos
de la línea de órdenes adicionales si lo consideráis
necesario, para poder separar las ejecuciones de padre
e hijo.
cambios2.h
. Las funciones proporcionadas por la
DLL que devuelven un entero, devuelven -1 en caso de error. A
continuación se ofrecen los prototipos de todas las funciones
incluidas en la DLL:
int inicioCambios(int ret, HANDLE mutex,
char *z)
ret
la velocidad de presentación
y pasando un manejador de un mutex (en estado de señalado)
para uso interno de la biblioteca
y el puntero a la zona de memoria
compartida recién creados.
int inicioCambiosHijo(int ret, HANDLE mutex,
char *z)
CreateProcess
en lugar de con
fork
, el proceso padre no puede dejar
variables "en herencia" al proceso recién creado.
Esto hace que el nuevo proceso tenga que hacerse con
los manejadores creados por el proceso padre y
el puntero a la zona de memoria compartida. No es
difícil lograrlo con las funciones de la familia
Open
..., como puede ser
OpenMutex
. Por la misma razón debe
el proceso hijo iniciar la DLL, obtener un puntero
a las funciones que quiera usar y llamar a la
función de inicio. No olvidemos que, por muy DLL
que sea, las variables internas son de un proceso
diferente al del padre (y por tanto de un espacio de
memoria virtual distinto) y deben ser iniciadas de nuevo,
al no poder haber sido heredadas como ocurría en UNIX.
Por consiguiente, el proceso hijo, después de obtener
las variables e iniciar la DLL, llamará a esta función,
en lugar de la que llamó el padre
(inicioCambios
).
int aQuEGrupo(int grupoActual)
int refrescar(void)
void incrementarCuenta(void)
int finCambios(void)
void pon_error(char *mensaje)
LONG
.
El desplazamiento desde el inicio de la zona de memoria compartida
será el mismo (84 bytes). Se puede usar más espacio de memoria
compartida si lo necesitáis.
#define
al inicio del código. Valores
razonables para esa capacidad están en los millares de mensajes.
cambios2.dll
cambios2.dll
y el fichero de cabeceras cambios2.h
.
cambios2.dll
ver. 1.0:
Descárgalo de aquí.
cambios2.h
:
Descárgalo de aquí.
EVENTOS Y VALOR INICIAL: EC* (automático), EV (automático). SEUDOCÓDIGO: C V === === Por_siempre_jamás Por _siempre_jamás { { W(EC) W(EV) escribir_consonante escribir_vocal Set(EV) Set(EC) } }Debéis indicar, asimismo, en el caso de que las hayáis realizado, las optimizaciones de código realizadas.
TerminateThread
para acabar con
los hilos o TerminateProcess
para acabar con
los procesos. El problema de estas funciones es que
están diseñada para ser usada sólo en condiciones
excepcionales y los hilos mueren abruptamente.
Puede dejar estructuras colgando, ir llenando
la memoria virtual del proceso con basura o no
invocar adecuadamente las funciones de descarga de la
DLL.
fprintf(stderr,...)
a
un fichero, añadiendo al final de la línea de órdenes
2>salida
. De este modo, toda la información
aparecerá en el fichero salida
para su
análisis posterior.
XXXX
de la biblioteca. No consigo de
ningún modo acceder a ella.XXXX
por lo que veremos más
abajo. Para definir el tipo de esta variable
correctamente, debéis conocer cómo son los
punteros a función. En la
sesión quinta,
se describe una función, atexit
.
Dicha función en sí no es importante para lo
que nos traemos entre manos, pero sí el argumento
que tiene. Ese argumento es un puntero a función.
Fijándoos en ese argumento, no os resultará
difícil generalizarlo para poner un puntero
a funciones que admiten otro tipo de parámetros
y devuelve otra cosa.
Notad, además, que, al contrario que
ocurre con las variables "normales", la definición
de una variable puntero a función es especial
por cuanto su definición no va sólo antes del
nombre de la variable, sino que lo rodea.
Tenéis que poner algo similar a:
#$%&%$ XXXX $%&$·@;
, es decir,
algo por delante y algo por detrás.
GetProcAddress
.
Pero, ¡cuidado!, GetProcAddress
devuelve un FARPROC
, que sólo
funciona con punteros a funciones que devuelven
int
y no se les pasa nada
(void)
. Debéis hacer el
correspondiente casting. Para ello,
de la definición de vuestro puntero, quitáis
el nombre, lo ponéis todo entre paréntesis
y lo añadís delante de
GetProcAddress
, como siempre.
XXXX
como nombre al puntero,
ahora no se diferenciarán en nada vuestras
llamadas a la función respecto a si dicha
función no perteneciera a una DLL y la
hubierais programado vosotros.
.h
si llamáis a vuestro
fichero fuente con extensión .c
. Llamadlo
siempre con extensión .cpp
.
libc
(malloc
y free
). Son funciones que no están
sincronizadas, es decir, no se comportan bien
en entornos multihilo. O bien las metéis en una
sección crítica o, mejor aún, tratad de evitarlas.