Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

copie lors d'un fork

20 réponses
Avatar
Sylvain SF
Bonjour,

ma question n'a pas son origine dans un point lié à C++ mais
ses conséquentes impactes un code C++.

soit une librairie partagée pouvant contenir de nombreux objets
(le fait qu'ils soient ou non copiable par code n'est pas le point ici).

cette lib. est utilisée par une application, cette liaison puis
l'utilisation de la lib. par cette appli. initialisent des objets
internes de la lib. (par interne je veux dire non public et donc
non connue de l'application externe) et quelques objets publics
(ici "objets" est générique, il signifiera le plus souvent que
l'application externe dispose d'un pointeur vers quelque chose
alloué et initialisé dans la librairie).

supposons maintenant que l'application fasse un fork, créant
un fils ("C") (supposons si besoin que C fasse aussi une
opération d'écriture pour avoir son propre espace mémoire).

ma question:
comment la librairie liée est effectivement forkée ?
dispose-t-elle également de son propre espace mémoire?
ie la représentation mémoire de la lib. lié par C est-elle
différente de celle liée par l'application parent ?
si la réponse est positive, je supposerais que cette
nouvelle copie est alors initialisée comme pour un
premier chargement (appel des constructeurs static
notamment).
si la réponse est négative, ou non définie, merci pour
une synthèse des possibles.

Sylvain.

10 réponses

1 2
Avatar
espie
In article <4a176a74$0$12613$,
Sylvain SF wrote:
Marc Espie a écrit :
In article <4a1714e0$0$17742$, Sylvain SF
wrote:
oui, ... euh, comment dit-on "GlobalAlloc" en POSIX dans le texte ?



La, j'espere que quelqu'un d'autre pourra t'aider, parce que je ne
parle pas windows...



ben, je posais la question à quelqu'un connaissant POSIX, pas windows
justement -- ok, "GlobalAlloc" alloue un bloc (à visibilité) global(e)
cela ne demande pas une forte connaissance de windows et on parlait
de cela:



Ah, okay, tu veux de la memoire partagee entre process.

Donc c'est du cote de mmap qu'il faut fouiller, avec MAP_SHARED

Et tu peux y mettre des semaphores posix

Les docs posix ne sont pas tres accessibles, mais tu as la doc Single Unix
disponible sur le reseau: http://www.unix.org/version3/
Avatar
James Kanze
On May 22, 9:05 pm, (Marc Espie) wrote:
In article <4a16f2e5$0$17769$,
Sylvain SF wrote:



>Marc Espie a écrit :



[...]
>j'ai parlé de librairie partagée (foo.so), je ne sais pas si
>tu emploies bibliothèque dans le même sens.



Librairie partagee, c'est un anglicisme.



« Shared library », c'est un nom mal approprié en anglais, étan t
donné que ce n'est pas une bibliothèque (et ne se comporte pas
comme une), et que ce n'est pas forcément partagée. « Objet
dynamique » serait plus correct.

Le terme francais est "bibliotheque".



Sauf que pour le concepte en question, le mot français serait
plutôt « objet ». (Il n'y a que chez Microsoft qu'on ne comprend
pas la distinction.)

Pour les "bibliotheques partagees", en fait, c'est plus le
concept fonctionnel qui a un sens, les systemes auxquels tu
auras affaire aujourd'hui (cote Unix) utilisent pratiquement
tous ELF, et elf n'a qu'un concept de "loadable module".
C'est avec ca que tu fais tes bibliotheques partagees, et tes
"plugins".



A part au chargement, Unix s'en fout: c'est soit un dlopen()
explicite, soit ton ld.so qui s'en charge. Il peut y avoir des
constructeurs (c'est d'ailleurs generalement l'horreur pour
que ca marche dans le bon ordre), mais il n'y a rien a voir
cote fork.



Que ce soit du Windows ou de Unix, une fois l'objet linké
(dynamiquement ou non), il fait partie du processus. Qu'il soit
linké dynamiquement ou statiquement, le résultat final est le
même.

[...]
>Marc Espie a écrit :
>> - les elements qui sont geres par le systeme. Typiquement,
>> les file descriptor qui sont lies a des structures internes
>> au noyau. Les fichiers ouverts sont "dupliques", mais le
>> systeme sait gerer le bout systeme.
>> - les primitives de gestion memoire, comme mmap, et les
>> gestions de semaphore correspondantes. La, tu peux demander
>> que la memoire soit partagee entre plusieurs process.



>yep, j'ai bien lu que certains descripteurs sont dupliqués
>d'autres non. reste à affiner et utiliser les bons.



Non, les descripteurs de fichiers sont toujours dupliques,



Sauf quand ils ne le sont pas. Il suffit d'un :
fcntl( fd, F_SETFD, FD_CLOEXEC ) ;
pour que le système ferme le ficher lors d'un exec.
(Logiquement, ça serait le defaut.)

>Marc Espie a écrit :
Non, juste apprendre et utiliser les appels systemes qui
gerent la memoire partagee et les semaphores, et voir comment
tu peux t'en servir dans le cas qui te concerne...



Et pourquoi pas pthread_atfork ?

--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Avatar
James Kanze
On May 22, 11:10 pm, Sylvain SF wrote:
Marc Espie a écrit :
> Non, juste apprendre et utiliser les appels systemes qui
> gerent la memoire partagee et les semaphores, et voir
> comment tu peux t'en servir dans le cas qui te concerne...



oui, ... euh, comment dit-on "GlobalAlloc" en POSIX dans le texte ?



On ne le dit pas. La fonction est d'ailleurs périmée sous
Windows -- selon Microsoft « The global and local functions are
supported for porting from 16-bit code, or for maintaining
source code compatibility with 16-bit Windows. » En gros, dans
des Windows modernes, GlobalAlloc se comporte exactement comme
HeapAlloc, seulement un peu plus lentement.

A priori, ce dont Marc parlait étaient des shmem fonctions, et
les sem fonctions. Dans la pratique, en revanche, je trouve
qu'elles sont très peu utilisées ; quand on veut de la mémoire
partagée, on utilise un mmap anonyme, et pour la synchronisation
entre processus, un mutex dans de la mémoire partagée.

Mais j'avoue ne pas voir trop de rapport avec ton problème. Le
modèle des processus sous Unix est assez perverse (avec fork,
plutôt qu'un spawn), avec des problèmes que tu es en train de
rencontrer. À mon avis :

-- Si tes IO sont des « character special files », et tu ne
veux qu'un processus en a accès, la solution la plus simple
serait de positionner le drappeau FD_CLOEXEC avec fcntl, dès
que tu l'ouvre. Dans ce cas-là, les processus fils auront
toujours les objets, dans l'état où ils étaient, mais tout
essaie de faire quelque chose avec les périphériques
échouera.

-- Sinon, tu peux utiliser pthread_atfork, pour marquer les
objets « invalids » dans le processus fils.

-- Sinon, tu peux bien mémoriser l'identificateur du processus
quand tu crées les objets, et le relire et comparer à chaque
accès.

Le plus simple, c'est clairement le premier. Les autres deux
permettront un code d'erreur plus parlant au client.

--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Avatar
James Kanze
On May 23, 9:48 am, (Marc Espie) wrote:
In article <4a176a74$0$12613$,
Les docs posix ne sont pas tres accessibles, mais tu as la doc
Single Unix disponible sur le
reseau:http://www.unix.org/version3/



Ce qui n'est pas la dernière édition. On est à
http://www.unix.org/2008edition/.

En revanche, beaucoup de systèmes ne sont pas encore à version
3. Avant d'utiliser quoique ce soit, je vérifierais aussi dans
les pages du man du système concerné.

Et c'est bien de la norme Posix qu'il s'agit. Ainsi que le
standard Unix ; le texte des deux est « unifié », avec des
balisages pour indiquer quand il ne s'agit que d'une.

--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Avatar
espie
In article ,
James Kanze wrote:
-- Si tes IO sont des « character special files », et tu ne
veux qu'un processus en a accès, la solution la plus simple
serait de positionner le drappeau FD_CLOEXEC avec fcntl, dès
que tu l'ouvre. Dans ce cas-là, les processus fils auront
toujours les objets, dans l'état où ils étaient, mais tout
essaie de faire quelque chose avec les périphériques
échouera.



Non, tu racontes n'importe quoi James (ca ne te ressemble pas).
Comme son nom l'indique, FD_CLOEXE ne va fermer le fd que lors d'un exec().
Il reste valide jusque-la. Ca s'adresse au nettoyage des fd de ton code
avant de passer le controle a un autre programme. Ca ne concerne pas le
cas present, puisqu'il s'agit du meme programme.

-- Sinon, tu peux utiliser pthread_atfork, pour marquer les
objets « invalids » dans le processus fils.



Valable uniquement pour du multi-threade, ce qui est une condition forte
a l'utilisation de sa bibliotheque...

-- Sinon, tu peux bien mémoriser l'identificateur du processus
quand tu crées les objets, et le relire et comparer à chaque
accès.



C'est la solution la moins hi-tech, et peut-etre la plus tout terrain...

Le plus simple, c'est clairement le premier. Les autres deux
permettront un code d'erreur plus parlant au client.



Si le premier fonctionnait, oui... mais il ne fait pas ce qu'on veut, et
donc...
Avatar
espie
In article ,
James Kanze wrote:
On May 22, 9:05 pm, (Marc Espie) wrote:
In article <4a16f2e5$0$17769$,
Sylvain SF wrote:



>Marc Espie a écrit :



[...]
>j'ai parlé de librairie partagée (foo.so), je ne sais pas si
>tu emploies bibliothèque dans le même sens.



Librairie partagee, c'est un anglicisme.



« Shared library », c'est un nom mal approprié en anglais, étant
donné que ce n'est pas une bibliothèque (et ne se comporte pas
comme une), et que ce n'est pas forcément partagée. « Objet
dynamique » serait plus correct.



C'est pour ca que je disais que le terme avait une connotation fonctionnelle:
les bibliotheques partagees sont les descendantes des bibliotheques classiques
et, bien souvent, tu vas avoir le meme code compile sous forme de bibliotheque
statique classique, et sous forme d'objet dynamique...

Le terme francais est "bibliotheque".



Sauf que pour le concepte en question, le mot français serait
plutôt « objet ». (Il n'y a que chez Microsoft qu'on ne comprend
pas la distinction.)



Pour les "bibliotheques partagees", en fait, c'est plus le
concept fonctionnel qui a un sens, les systemes auxquels tu
auras affaire aujourd'hui (cote Unix) utilisent pratiquement
tous ELF, et elf n'a qu'un concept de "loadable module".
C'est avec ca que tu fais tes bibliotheques partagees, et tes
"plugins".





Exactement ce que je dis, quoi ;-)

A part au chargement, Unix s'en fout: c'est soit un dlopen()
explicite, soit ton ld.so qui s'en charge. Il peut y avoir des
constructeurs (c'est d'ailleurs generalement l'horreur pour
que ca marche dans le bon ordre), mais il n'y a rien a voir
cote fork.



Que ce soit du Windows ou de Unix, une fois l'objet linké
(dynamiquement ou non), il fait partie du processus. Qu'il soit
linké dynamiquement ou statiquement, le résultat final est le
même.

[...]
>Marc Espie a écrit :
>> - les elements qui sont geres par le systeme. Typiquement,
>> les file descriptor qui sont lies a des structures internes
>> au noyau. Les fichiers ouverts sont "dupliques", mais le
>> systeme sait gerer le bout systeme.
>> - les primitives de gestion memoire, comme mmap, et les
>> gestions de semaphore correspondantes. La, tu peux demander
>> que la memoire soit partagee entre plusieurs process.



>yep, j'ai bien lu que certains descripteurs sont dupliqués
>d'autres non. reste à affiner et utiliser les bons.



Non, les descripteurs de fichiers sont toujours dupliques,



Sauf quand ils ne le sont pas. Il suffit d'un :
fcntl( fd, F_SETFD, FD_CLOEXEC ) ;
pour que le système ferme le ficher lors d'un exec.
(Logiquement, ça serait le defaut.)



Uniquement lors d'un exec... la on parle de deux processus qui partagent
le meme code, dont un bout est sous controle du developpeur, et le reste
sous controle de l'utilisateur.


>Marc Espie a écrit :
Non, juste apprendre et utiliser les appels systemes qui
gerent la memoire partagee et les semaphores, et voir comment
tu peux t'en servir dans le cas qui te concerne...



Et pourquoi pas pthread_atfork ?



Ca suppose qu'on veuille d'office faire du multi-threade, ce qui a un cout.
- ca n'est pas toujours implemente de facon efficace.
- ca peut etre buggue.
- il y a souvent des options de compilation en plus pour faire du multi-threade.
=> c'est donc une contrainte supplementaire pour l'utilisateur final (en
supposant que le code de bibliotheque ne soit pas deja multi-threade).

Certaines bibliotheques, comme sqlite, savent gerer ce genre de choses (on
peut avoir les verrous qui sont sous controle d'un symbole "faible" pour marcher
en multi-threade, et devenir "rien" en mono-thread), mais ce n'est pas vraiment
ce qu'on veut ici, puisqu'on veut RAJOUTER quelque chose autour de fork(),
qu'on soit en monothread ou pas... et en monothread, ca sera impossible, a part
wrapper manuellement quelque chose autour de fork()... et c'est pas trop
extensible, je ne te dis pas le bazar si tout concepteur de bibliotheque dit
"ah oui, mais si vous appelez fork(), il faut appeler ma fonction a la place".
Avatar
Sylvain SF
Marc Espie a écrit :
Non, juste apprendre et utiliser les appels systemes qui
gerent la memoire partagee et les semaphores, et voir comment
tu peux t'en servir dans le cas qui te concerne...


Et pourquoi pas pthread_atfork ?



Ca suppose qu'on veuille d'office faire du multi-threade, ce qui a un cout.



["multi-threade" est aussi un anglicisme ?]

je ne lis pas que pthread_atfork soit réservé à du code MT, il est
seulement présenté comme une solution possible aux problèmes courants
des codes MT. ma lib. est d'office multi-thread, elle ne le serait
pas que pthread_atfork semblerait une option possible, je ne suis
pour autant pas sur d'un point, est-ce que la lib. peut invoquer
pthread_atfork avec la même liberté que le process (principal)
ayant monté cette lib. ?

Sylvain.
Avatar
James Kanze
On May 23, 11:54 pm, (Marc Espie) wrote:
In article com>,
James Kanze wrote:



> -- Si tes IO sont des « character special files », et tu ne
> veux qu'un processus en a accès, la solution la plus simple
> serait de positionner le drappeau FD_CLOEXEC avec fcntl, dès
> que tu l'ouvre. Dans ce cas-là, les processus fils auront
> toujours les objets, dans l'état où ils étaient, mais tout
> essaie de faire quelque chose avec les périphériques
> échouera.



Non, tu racontes n'importe quoi James (ca ne te ressemble
pas). Comme son nom l'indique, FD_CLOEXE ne va fermer le fd
que lors d'un exec().



En effet. Je ne sais pas à quoi je pensais.

> -- Sinon, tu peux utiliser pthread_atfork, pour marquer les
> objets « invalids » dans le processus fils.



Valable uniquement pour du multi-threade, ce qui est une
condition forte a l'utilisation de sa bibliotheque...



Ça dépend un peu de la bibliotheque. Je me sers de beaucoup de
bibliotheques qui utilisent elles-même des threads.

> -- Sinon, tu peux bien mémoriser l'identificateur du processus
> quand tu crées les objets, et le relire et comparer à chaque
> accès.



C'est la solution la moins hi-tech, et peut-etre la plus tout
terrain...



C'est certainement la plus simple et la plus robuste.

--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Avatar
James Kanze
On May 24, 3:01 am, Sylvain SF wrote:
Marc Espie a écrit :



>>> Non, juste apprendre et utiliser les appels systemes qui
>>> gerent la memoire partagee et les semaphores, et voir comment
>>> tu peux t'en servir dans le cas qui te concerne...
>> Et pourquoi pas pthread_atfork ?



> Ca suppose qu'on veuille d'office faire du multi-threade, ce qui a un c out.



["multi-threade" est aussi un anglicisme ?]



je ne lis pas que pthread_atfork soit réservé à du code MT, il
est seulement présenté comme une solution possible aux
problèmes courants des codes MT. ma lib. est d'office
multi-thread, elle ne le serait pas que pthread_atfork
semblerait une option possible, je ne suis pour autant pas sur
d'un point, est-ce que la lib. peut invoquer pthread_atfork
avec la même liberté que le process (principal) ayant monté
cette lib. ?



Elle fait partie de l'option « threads ». C'est vrai que Posix
n'en dit pas beaucoup sur les critère d'activation de cette
option, mais dans la pratique, avec beaucoup de compilateurs, il
faut une option supplémentaire (-mt, ou quelque chose du genre),
et qu'il faut que toutes les modules soient compilées avec cette
option. (Mais ça dépend du compilateur.) Et comme Marc dit,
cette option introduit parfois des coûts supplémentaires. Sous
Solaris avec Sun CC, si je me souviens correctement, si tu
spécifies -mt, le compilateur s'arrange pour que tu n'aies pas
accès à des fonctions non-thread-safe, comme localtime(). Et si
tu ne le spécifie pas, toutes les fonctions dans <pthread>
devient des no-ops, qui renvoient un code d'erreur. (Mais je
peux me tromper ; ça fait un moment depuis que je me suis penché
sur le problème.)

--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Avatar
espie
Je suis sur un systeme ou les threads sont suffisamment differents du systeme
de base pour savoir qu'il faut des options explicites pour activer ceux-ci.
(au depart, pthread est quand meme une bibliotheque userland).

Et fork, l'appel systeme, ne connait pas pthread_atfork, du tout.
Dans cette implementation, lorsqu'on active les threads, la plupart des
appels systeme sont "wrappes" dans du code supplementaire pour faire
fonctionner les threads, dont fork.

Si tu y melanges du code compile avec pthread et sans pthread, ca fait
n'importe quoi...

Une implementation purement noyau des threads peut occasionner quelques soucis,
la gestion des signaux n'est pas simple du tout. Linux a suivi il y a quelques
annees la voie opposee: il y existe un appel systeme de creation de "trucs"
(clone), et cet appel systeme se specialise en process/threads/whatever
selon le cas.
1 2