Am Ende steht ein tl;dr.
In meinem Kommentar habe ich dir mmap()
vorgeschlagen die /dev/null
Gerät. Es scheint jedoch, dass das Gerät auf meinem Computer nicht kartierbar ist (Fehler 19
:No such device
). Es sieht aus wie /dev/zero
ist aber abbildbar. Eine andere Frage/Antwort legt nahe, dass dies äquivalent zu MAP_ANONYMOUS
ist was den fd
ergibt -Argument und dem zugehörigen open()
erstmal unnötig. Sehen Sie sich ein Beispiel an:
#include <iostream>
#include <cstring>
#include <cerrno>
#include <cstdlib>
extern "C" {
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <fcntl.h>
}
template <class Type>
struct iovec ignored(void *p)
{
struct iovec iov_ = {};
iov_.iov_base = p;
iov_.iov_len = sizeof(Type);
return iov_;
}
int main()
{
auto * p = mmap(nullptr, 4096, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if ( MAP_FAILED == p ) {
auto err = errno;
std::cerr << "mmap(MAP_PRIVATE | MAP_ANONYMOUS): " << err << ": " << strerror(err) << std::endl;
return EXIT_FAILURE;
}
int s_[2] = {-1, -1};
int result = socketpair(AF_UNIX, SOCK_STREAM, 0, s_);
if ( result < 0 ) {
auto err = errno;
std::cerr << "socketpair(): " << err << ": " << strerror(err) << std::endl;
return EXIT_FAILURE;
}
int w_[3] = {1,2,3};
ssize_t nwritten = 0;
auto makeiov = [](int & v){
struct iovec iov_ = {};
iov_.iov_base = &v;
iov_.iov_len = sizeof(v);
return iov_;
};
struct iovec wv[3] = {
makeiov(w_[0]),
makeiov(w_[1]),
makeiov(w_[2])
};
nwritten = writev(s_[0], wv, 3);
if ( nwritten < 0 ) {
auto err = errno;
std::cerr << "writev(): " << err << ": " << strerror(err) << std::endl;
return EXIT_FAILURE;
}
int r_ = {0};
ssize_t nread = 0;
struct iovec rv[3] = {
ignored<int>(p),
makeiov(r_),
ignored<int>(p),
};
nread = readv(s_[1], rv, 3);
if ( nread < 0 ) {
auto err = errno;
std::cerr << "readv(): " << err << ": " << strerror(err) << std::endl;
return EXIT_FAILURE;
}
std::cout <<
w_[0] << '\t' <<
w_[1] << '\t' <<
w_[2] << '\n' <<
r_ << '\t' <<
*(int*)p << std::endl;
return EXIT_SUCCESS;
}
Im obigen Beispiel sehen Sie, dass ich eine private erstelle (Schreibvorgänge sind für Kinder nach fork()
nicht sichtbar ) Anonyme (nicht durch eine Datei gesicherte) Speicherzuordnung von 4KiB (eine einzelne Seitengröße auf den meisten Systemen). Es wird dann zweimal verwendet, um ein Schreibziel für zwei Ints bereitzustellen – wobei das spätere Int das frühere überschreibt.
Das stimmt nicht genau lösen Sie Ihre Frage:wie man die Bytes ignoriert. Da Sie readv()
verwenden , habe ich mir die Schwesterfunktion preadv()
angesehen was auf den ersten Blick das zu tun scheint, was Sie wollen:Bytes überspringen. Es scheint jedoch, dass dies von Socket-Dateideskriptoren nicht unterstützt wird. Der folgende Code ergibt preadv(): 29: Illegal seek
.
rv = makeiov(r_[1]);
nread = preadv(s_[1], &rv, 1, sizeof(int));
if ( nread < 0 ) {
auto err = errno;
std::cerr << "preadv(): " << err << ": " << strerror(err) << std::endl;
return EXIT_FAILURE;
}
Es sieht also aus wie preadv()
verwendet seek()
unter der Haube, was an einer Steckdose natürlich nicht erlaubt ist. Ich bin mir nicht sicher, ob es (noch?) Eine Möglichkeit gibt, dem Betriebssystem mitzuteilen, dass es in einem etablierten Stream empfangene Bytes ignorieren/verwerfen soll. Ich vermute, das liegt daran, dass @geza richtig ist:Die Kosten für das Schreiben an das endgültige (ignorierte) Ziel sind in den meisten Situationen, denen ich begegnet bin, äußerst trivial. Und in den Situationen, in denen die Kosten der ignorierten Bytes nicht sind trivial, sollten Sie ernsthaft überlegen, bessere Optionen, Implementierungen oder Protokolle zu verwenden.
tl;dr:
Das Erstellen einer anonymen privaten 4KiB-Speicherzuordnung ist praktisch nicht von Contiguous-Allocation-Containern zu unterscheiden (es gibt subtile Unterschiede, die für jede Workload außerhalb der sehr hohen Leistung wahrscheinlich nicht wichtig sind). Die Verwendung eines Standardcontainers ist auch viel weniger anfällig für Zuordnungsfehler:Speicherlecks, wilde Zeiger usw. Also würde ich KISS sagen und einfach das tun anstatt beliebige zu unterstützen des Codes, den ich oben geschrieben habe. Beispiel:std::array<char, 4096> ignored;
oder std::vector<char> ignored{4096};
und einfach iovec.iov_base = ignored.data();
einstellen und setze den .iov_len
auf die Größe, die Sie ignorieren müssen (innerhalb der Länge des Containers).