Для приложения, которое я разрабатываю (под Linux, но я пытаюсь поддерживать переносимость), мне нужно переключиться на разделяемую память для обмена данными между различными процессами (и потоками внутри процессов). Есть процесс отца, порождающий разных детей
Мне нужно, например, чтобы каждый процесс мог увеличивать общий счетчик, используя именованный семафор.
В этом случае все в порядке:
#include <sys/mman.h>
#include <sys/wait.h>
#include <semaphore.h>
#include <fcntl.h>
#include <iostream>
#include <stdlib.h>
#include <string.h>
using namespace std;
#define SEM_NAME "/mysem"#define SM_NAME "tmp_sm.txt"
int main(){
int fd, nloop, counter_reset;
int *smo;
sem_t *mutex;
nloop = 100;
counter_reset = 1000;
if (fork() == 0) {
/* child */
/* create, initialize, and unlink semaphore */
mutex = sem_open(SEM_NAME, O_CREAT, 0777, 1);
//sem_unlink(SEM_NAME);
/* open file, initialize to 0, map into memory */
fd = open(SM_NAME, O_RDWR | O_CREAT);
smo = (int *) mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
close(fd);
/* INCREMENT */
for (int i = 0; i < nloop; i++) {
sem_wait(mutex);
cout << "child: " << (*smo)++ << endl;
if(*smo>=counter_reset){
(*smo)=0;
}
sem_post(mutex);
}
exit(0);
}
/* parent */
/* create, initialize, and unlink semaphore */
mutex = sem_open(SEM_NAME, O_CREAT, 0777, 1);
sem_unlink(SEM_NAME);
/* open file, initialize to 0, map into memory */
fd = open(SM_NAME, O_RDWR | O_CREAT);
smo = (int *) mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
close(fd);
/* INCREMENT */
for (int i = 0; i < nloop; i++) {
sem_wait(mutex);
cout << "parent: " << (*smo)++ << endl;
if(*smo>=counter_reset){
(*smo)=0;
}
sem_post(mutex);
}
exit(0);
}
Пока все хорошо: и семафор, и общий счетчик в порядке (один и тот же адрес в памяти), а инкремент и сброс работают нормально.
Программа завершается ошибкой, просто перемещая дочерний исходный код в новый исходный файл, вызываемый exec. Адреса совместно используемой памяти и именованных семафоров различны, поэтому приращение не выполняется.
Любое предложение? Я использовал именованные семафоры и именованную разделяемую память (используя файл), чтобы попытаться получить те же значения указателя.
ОБНОВИТЬ:
в соответствии с запросом Joachim Pileborg, это усовершенствования «на стороне сервера» выше оригинального кода:
...
if (fork() == 0) {
/* child */
/*spawn child by execl*/
char cmd[] = "/path_to_bin/client";
execl(cmd, cmd, (char *)0);
cerr << "error while istantiating new process" << endl;
exit(EXIT_FAILURE);
}
...
И это «клиентский» исходный код:
#include <sys/mman.h>
#include <sys/wait.h>
#include <semaphore.h>
#include <fcntl.h>
#include <iostream>
#include <stdlib.h>
using namespace std;
#define SEM_NAME "/mysem"#define SM_NAME "tmp_ssm.txt"
int main(){
int nloop, counter_reset;
int *smo;
sem_t *mutex;
/* create, initialize, and unlink semaphore */
mutex = sem_open(SEM_NAME, O_CREAT, 0777, 1);
//sem_unlink(SEM_NAME);
/* open file, initialize to 0, map into memory */
int fd = open(SM_NAME, O_RDWR | O_CREAT);
smo = (int *) mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
close(fd);
nloop=100;
counter_reset=1000;
/* INCREMENT */
for (int i = 0; i < nloop; i++) {
sem_wait(mutex);
cout << "child: " << (*smo)++ << endl;
if(*smo>=counter_reset){
(*smo)=0;
}
sem_post(mutex);
}
exit(0);
}
выполнение этого кода приводит к тому, что процесс блокируется (тупик) и ожидает бесконечное время. глядя на адреса, они обычно обнаруживаются:
father semaphore: 0x7f2fe1813000
child semahpore: 0x7f0c4c793000
father shared memory: 0x7f2fe1811000
child shared memory: 0x7ffd175cb000
удаление ‘sem_post’ и ‘sem_wait’ все хорошо, но мне нужно взаимное исключение при увеличении …
Не отсоединяйте семафор. это фактически удаляет семафор.
От sem_unlink
страница справочника:
sem_unlink () удаляет указанный семафор, указанный по имени. Имя семафора удаляется немедленно. Семафор уничтожается, как только все остальные процессы, у которых этот семафор открыт, закрываются.
Это означает, что как только вы создали семафор в родительском процессе, вы немедленно удалите его. Тогда дочерний процесс не сможет найти семафор, а вместо этого создаст новый.
Других решений пока нет …