如何从子进程写入共享内存
How to write into shared memory from a child process
我正在试验子进程,因为这似乎是并行制作不能在线程中使用的旧 C 库 运行 的唯一方法。
我的最小示例将三个整数值写入映射内存。在子进程中,我想更改这些值。更改最后一个(第三个)值有效,但仅更改第二个值时我收到此输出错误:
initial mapped memory in parent process: 000000000000000000000000000000010000000000000000000000000000001000000000000000000000000000000011
mapped memory in child process before writing: 000000000000000000000000000000010000000000000000000000000000001000000000000000000000000000000011
mapped memory in child process after writing: 0000000000000000000000000000000100000000000000000000000000011011
mapped memory in parent process after child process finished: 0000000000000000000000000000000100000000000000000000000000011011
1
27
terminate called after throwing an instance of 'std::invalid_argument'
what(): bitset::_M_copy_from_ptr
Process finished with exit code 134 (interrupted by signal 6: SIGABRT)
最小的代码示例是这样的:
#include <iostream>
#include <vector>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <bitset>
#include <semaphore.h>
using namespace std;
int main(int /*argc*/, char* /*argv*/[])
{
const char * shm_name = "/a_shm_name";
const int SIZE = 4096;
std::vector<int> v{1, 2, 3};
int shm_fd = shm_open(shm_name, O_CREAT | O_RDWR, 0666);
ftruncate(shm_fd, 32 * v.size());
void * ptr0 = mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
//write into the memory segment
void * ptr = ptr0;
for(int i = 0; i < v.size(); i++)
{
std::string s = std::bitset<32>(v[i]).to_string();
int count = sprintf((char*)ptr, "%s", s.c_str());
ptr = ptr + count;
}
cout << "initial mapped memory in parent process: " << (char*)ptr0 << endl << flush;
//fork
int n1 = fork();
if(n1 == 0)
{
//client process
shm_fd = shm_open(shm_name, O_CREAT | O_RDWR, 0666);
ptr0 = mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
cout << "mapped memory in child process before writing: " << (char*)ptr0 << endl << flush;
//write into the memory segment
//sem_wait(semId);
ptr = ptr0 + 32 * 1;
sprintf((char*)ptr, "%s", std::bitset<32>(27).to_string().c_str());
cout << "mapped memory in child process after writing: " << (char*)ptr0 << endl << flush;
exit(0);
}
else
{
//parent process
wait(nullptr);
}
//child process finished, back in the parent process
//client process
shm_fd = shm_open(shm_name, O_RDONLY, 0666);
ptr = mmap(0, SIZE, PROT_READ, MAP_SHARED, shm_fd, 0);
cout << "mapped memory in parent process after child process finished: " << (char*)ptr0 << endl << flush;
for(int i = 0; i < v.size(); i++)
{
cout << std::bitset<32>(std::string((char*)ptr, 32)).to_ulong() << endl;
ptr = ptr + 32;
}
munmap(ptr0, SIZE);
shm_unlink(shm_name);
return 0;
}
我有两个问题:
- 为什么我不能只更改第二个整数值?
- 是否有更好的技术在单独的子进程之间共享数据?
这与进程或 mmap
根本无关:Simpler program with similar results.
#include <vector>
#include <bitset>
#include <iostream>
int main() {
using std::cout, std::endl, std::flush;
const int SIZE = 4096;
std::vector<int> v{1, 2, 3};
char buffer[SIZE];
char * ptr0 = buffer;
//write into the memory segment
char * ptr = ptr0;
for(unsigned int i = 0; i < v.size(); i++)
{
std::string s = std::bitset<32>(v[i]).to_string();
int count = sprintf(ptr, "%s", s.c_str());
ptr = ptr + count;
}
cout << "initial memory: " << ptr0 << endl << flush;
//write into the memory segment
ptr = ptr0 + 32 * 1;
sprintf(ptr, "%s", std::bitset<32>(27).to_string().c_str());
cout << "mapped memory in child process after writing: " << ptr0 << endl << flush;
}
(我将所有 void*
更改为 char*
,因为将数字添加到 void*
不是标准 C++,尽管一些编译器有扩展将其视为添加到 char*
.)
sprintf
在实际输出结束后写入一个空终止符。因此,当您使用它在子项中写入 "the second value" 时,它会将 '[=18=]'
放入 "the third value" 的第一个字节中。此外,您实际上一直依赖 "the third value" 之后 ((char*)ptr0)[3*32]
处的 '[=18=]'
来了解 std::cout
何时停止打印。
而不是 sprintf
和 operator<<
和 const char*
,它们都是用于以 null 结尾的字符串,我建议只复制字节的函数:
std::string data = std::bitset<32>(value).to_string();
std::copy(data.begin(), data.end(), (char*) ptr);
cout.write((char*) ptr, 32);
我正在试验子进程,因为这似乎是并行制作不能在线程中使用的旧 C 库 运行 的唯一方法。
我的最小示例将三个整数值写入映射内存。在子进程中,我想更改这些值。更改最后一个(第三个)值有效,但仅更改第二个值时我收到此输出错误:
initial mapped memory in parent process: 000000000000000000000000000000010000000000000000000000000000001000000000000000000000000000000011
mapped memory in child process before writing: 000000000000000000000000000000010000000000000000000000000000001000000000000000000000000000000011
mapped memory in child process after writing: 0000000000000000000000000000000100000000000000000000000000011011
mapped memory in parent process after child process finished: 0000000000000000000000000000000100000000000000000000000000011011
1
27
terminate called after throwing an instance of 'std::invalid_argument'
what(): bitset::_M_copy_from_ptr
Process finished with exit code 134 (interrupted by signal 6: SIGABRT)
最小的代码示例是这样的:
#include <iostream>
#include <vector>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <bitset>
#include <semaphore.h>
using namespace std;
int main(int /*argc*/, char* /*argv*/[])
{
const char * shm_name = "/a_shm_name";
const int SIZE = 4096;
std::vector<int> v{1, 2, 3};
int shm_fd = shm_open(shm_name, O_CREAT | O_RDWR, 0666);
ftruncate(shm_fd, 32 * v.size());
void * ptr0 = mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
//write into the memory segment
void * ptr = ptr0;
for(int i = 0; i < v.size(); i++)
{
std::string s = std::bitset<32>(v[i]).to_string();
int count = sprintf((char*)ptr, "%s", s.c_str());
ptr = ptr + count;
}
cout << "initial mapped memory in parent process: " << (char*)ptr0 << endl << flush;
//fork
int n1 = fork();
if(n1 == 0)
{
//client process
shm_fd = shm_open(shm_name, O_CREAT | O_RDWR, 0666);
ptr0 = mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
cout << "mapped memory in child process before writing: " << (char*)ptr0 << endl << flush;
//write into the memory segment
//sem_wait(semId);
ptr = ptr0 + 32 * 1;
sprintf((char*)ptr, "%s", std::bitset<32>(27).to_string().c_str());
cout << "mapped memory in child process after writing: " << (char*)ptr0 << endl << flush;
exit(0);
}
else
{
//parent process
wait(nullptr);
}
//child process finished, back in the parent process
//client process
shm_fd = shm_open(shm_name, O_RDONLY, 0666);
ptr = mmap(0, SIZE, PROT_READ, MAP_SHARED, shm_fd, 0);
cout << "mapped memory in parent process after child process finished: " << (char*)ptr0 << endl << flush;
for(int i = 0; i < v.size(); i++)
{
cout << std::bitset<32>(std::string((char*)ptr, 32)).to_ulong() << endl;
ptr = ptr + 32;
}
munmap(ptr0, SIZE);
shm_unlink(shm_name);
return 0;
}
我有两个问题:
- 为什么我不能只更改第二个整数值?
- 是否有更好的技术在单独的子进程之间共享数据?
这与进程或 mmap
根本无关:Simpler program with similar results.
#include <vector>
#include <bitset>
#include <iostream>
int main() {
using std::cout, std::endl, std::flush;
const int SIZE = 4096;
std::vector<int> v{1, 2, 3};
char buffer[SIZE];
char * ptr0 = buffer;
//write into the memory segment
char * ptr = ptr0;
for(unsigned int i = 0; i < v.size(); i++)
{
std::string s = std::bitset<32>(v[i]).to_string();
int count = sprintf(ptr, "%s", s.c_str());
ptr = ptr + count;
}
cout << "initial memory: " << ptr0 << endl << flush;
//write into the memory segment
ptr = ptr0 + 32 * 1;
sprintf(ptr, "%s", std::bitset<32>(27).to_string().c_str());
cout << "mapped memory in child process after writing: " << ptr0 << endl << flush;
}
(我将所有 void*
更改为 char*
,因为将数字添加到 void*
不是标准 C++,尽管一些编译器有扩展将其视为添加到 char*
.)
sprintf
在实际输出结束后写入一个空终止符。因此,当您使用它在子项中写入 "the second value" 时,它会将 '[=18=]'
放入 "the third value" 的第一个字节中。此外,您实际上一直依赖 "the third value" 之后 ((char*)ptr0)[3*32]
处的 '[=18=]'
来了解 std::cout
何时停止打印。
而不是 sprintf
和 operator<<
和 const char*
,它们都是用于以 null 结尾的字符串,我建议只复制字节的函数:
std::string data = std::bitset<32>(value).to_string();
std::copy(data.begin(), data.end(), (char*) ptr);
cout.write((char*) ptr, 32);