google-site-verification: google61fe8ba583a51912.html
Advanced I/O Operations in C: Mastering Input/Output for High-Performance Applications

Introduction

Input/Output operations are fundamental to almost every C program, yet many developers only scratch the surface of what's possible. From memory-mapped files to asynchronous I/O, from scatter-gather operations to advanced buffering strategies, mastering advanced I/O techniques can dramatically improve application performance. This comprehensive guide explores the full spectrum of I/O operations in C.


1. Memory-Mapped I/O (mmap)

1.1 Basic Memory Mapping

#include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <sys/mman.h> #include <sys/stat.h> #include <unistd.h> #include <string.h> #include <errno.h> void* map_file(const char *filename, size_t *size) { int fd = open(filename, O_RDWR); if (fd == -1) { perror("open"); return NULL; } // Get file size struct stat st; if (fstat(fd, &st) == -1) { perror("fstat"); close(fd); return NULL; } *size = st.st_size; // Memory map the file void *addr = mmap(NULL, *size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (addr == MAP_FAILED) { perror("mmap"); close(fd); return NULL; } close(fd); // Can close fd after mapping return addr; } void unmap_file(void *addr, size_t size) { if (munmap(addr, size) == -1) { perror("munmap"); } } int main() { size_t size; char *data = map_file("example.txt", &size); if (data == NULL) { return 1; } // Modify file directly in memory printf("File contents: %.*s\n", (int)size, data); strcpy(data, "Modified content!\n"); // Changes are automatically written to disk (with MAP_SHARED) unmap_file(data, size); return 0; }

1.2 Private vs Shared Mappings

void demonstrate_mmap_types(void) { int fd = open("data.bin", O_RDWR | O_CREAT, 0644); if (fd == -1) return; // MAP_SHARED - changes written back to file void *shared = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); // MAP_PRIVATE - changes stay in memory (copy-on-write) void *private = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); // MAP_ANONYMOUS - no file backing (like malloc) void *anonymous = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); // Use mappings... munmap(shared, 4096); munmap(private, 4096); munmap(anonymous, 4096); close(fd); }

1.3 Large File Support with mmap

#include <sys/mman.h> #include <fcntl.h> #define FILE_SIZE (10ULL * 1024 * 1024 * 1024) // 10 GB void process_large_file(void) { int fd = open("large_file.dat", O_RDWR | O_CREAT, 0644); if (fd == -1) return; // Extend file to desired size if (ftruncate(fd, FILE_SIZE) == -1) { perror("ftruncate"); close(fd); return; } // Map the entire file (may require 64-bit addressing) void *addr = mmap(NULL, FILE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (addr == MAP_FAILED) { perror("mmap"); close(fd); return; } // Process file in chunks size_t chunk_size = 1024 * 1024; // 1 MB chunks for (size_t offset = 0; offset < FILE_SIZE; offset += chunk_size) { size_t remaining = FILE_SIZE - offset; size_t process = remaining < chunk_size ? remaining : chunk_size; // Direct access to file data via addr + offset char *chunk = (char*)addr + offset; // Process chunk... memset(chunk, 0xFF, process); } munmap(addr, FILE_SIZE); close(fd); }

2. Scatter-Gather I/O (readv/writev)

2.1 Basic readv/writev Usage

#include <sys/uio.h> #include <fcntl.h> #include <unistd.h> #include <stdio.h> void scatter_gather_example(void) { int fd = open("data.txt", O_RDWR | O_CREAT, 0644); if (fd == -1) return; // Prepare scatter/gather vectors struct iovec iov[3]; char header[32]; char body[1024]; char footer[32]; iov[0].iov_base = header; iov[0].iov_len = sizeof(header); iov[1].iov_base = body; iov[1].iov_len = sizeof(body); iov[2].iov_base = footer; iov[2].iov_len = sizeof(footer); // Write all buffers in one system call ssize_t nwritten = writev(fd, iov, 3); if (nwritten == -1) { perror("writev"); } else { printf("Wrote %zd bytes\n", nwritten); } // Reset file position lseek(fd, 0, SEEK_SET); // Read into scattered buffers ssize_t nread = readv(fd, iov, 3); if (nread == -1) { perror("readv"); } else { printf("Read %zd bytes\n", nread); printf("Header: %.*s\n", (int)sizeof(header), header); printf("Body: %.*s\n", (int)sizeof(body), body); printf("Footer: %.*s\n", (int)sizeof(footer), footer); } close(fd); }

2.2 Advanced Scatter-Gather with Dynamic Buffers

#include <sys/uio.h> #include <stdlib.h> typedef struct { struct iovec *vectors; int count; size_t total_size; } ScatterGatherList; ScatterGatherList* create_scatter_gather(int max_vectors) { ScatterGatherList *sg = malloc(sizeof(ScatterGatherList)); sg->vectors = calloc(max_vectors, sizeof(struct iovec)); sg->count = 0; sg->total_size = 0; return sg; } void add_buffer(ScatterGatherList *sg, void *buffer, size_t size) { sg->vectors[sg->count].iov_base = buffer; sg->vectors[sg->count].iov_len = size; sg->total_size += size; sg->count++; } ssize_t writev_all(int fd, ScatterGatherList *sg) { ssize_t total_written = 0; int i = 0; while (i < sg->count) { ssize_t written = writev(fd, &sg->vectors[i], sg->count - i); if (written == -1) { return -1; } total_written += written; // Adjust remaining vectors size_t remaining = written; while (i < sg->count && remaining >= sg->vectors[i].iov_len) { remaining -= sg->vectors[i].iov_len; i++; } if (i < sg->count && remaining > 0) { sg->vectors[i].iov_base = (char*)sg->vectors[i].iov_base + remaining; sg->vectors[i].iov_len -= remaining; } } return total_written; }

3. Asynchronous I/O (AIO)

3.1 POSIX AIO Basics

#include <aio.h> #include <fcntl.h> #include <signal.h> #include <unistd.h> #include <string.h> #include <stdio.h> #include <errno.h> volatile int aio_complete = 0; void aio_completion_handler(sigval_t sigval) { struct aiocb *req = (struct aiocb*)sigval.sival_ptr; // Check status int ret = aio_error(req); if (ret == 0) { ssize_t bytes = aio_return(req); printf("AIO completed: %zd bytes\n", bytes); } aio_complete = 1; } void async_read_example(void) { int fd = open("data.txt", O_RDONLY); if (fd == -1) return; struct aiocb cb; char buffer[4096]; memset(&cb, 0, sizeof(cb)); cb.aio_fildes = fd; cb.aio_buf = buffer; cb.aio_nbytes = sizeof(buffer); cb.aio_offset = 0; // Set up completion notification cb.aio_sigevent.sigev_notify = SIGEV_THREAD; cb.aio_sigevent.sigev_notify_function = aio_completion_handler; cb.aio_sigevent.sigev_value.sival_ptr = &cb; // Start async read if (aio_read(&cb) == -1) { perror("aio_read"); close(fd); return; } printf("Waiting for async read to complete...\n"); // Wait for completion while (!aio_complete) { // Do other work usleep(10000); } close(fd); }

3.2 AIO with Polling

#include <aio.h> #include <poll.h> void aio_poll_example(void) { int fd = open("large_file.dat", O_RDONLY); if (fd == -1) return; struct aiocb *cbs[10]; char buffers[10][4096]; // Start multiple async reads for (int i = 0; i < 10; i++) { struct aiocb *cb = malloc(sizeof(struct aiocb)); memset(cb, 0, sizeof(struct aiocb)); cb->aio_fildes = fd; cb->aio_buf = buffers[i]; cb->aio_nbytes = sizeof(buffers[i]); cb->aio_offset = i * sizeof(buffers[i]); if (aio_read(cb) == -1) { perror("aio_read"); free(cb); continue; } cbs[i] = cb; } // Poll for completion int pending = 10; while (pending > 0) { for (int i = 0; i < 10; i++) { if (cbs[i] == NULL) continue; int ret = aio_error(cbs[i]); if (ret == 0) { // Completed ssize_t bytes = aio_return(cbs[i]); printf("Read %zd bytes from offset %lld\n", bytes, cbs[i]->aio_offset); free(cbs[i]); cbs[i] = NULL; pending--; } else if (ret != EINPROGRESS) { // Error perror("aio_error"); free(cbs[i]); cbs[i] = NULL; pending--; } } usleep(10000); // Wait a bit before polling again } close(fd); }

4. Non-Blocking I/O and epoll

4.1 Setting Non-Blocking Mode

#include <fcntl.h> #include <unistd.h> #include <errno.h> int set_nonblocking(int fd) { int flags = fcntl(fd, F_GETFL, 0); if (flags == -1) { return -1; } return fcntl(fd, F_SETFL, flags | O_NONBLOCK); } void nonblocking_read_example(void) { int fd = open("data.txt", O_RDONLY); if (fd == -1) return; set_nonblocking(fd); char buffer[1024]; while (1) { ssize_t n = read(fd, buffer, sizeof(buffer)); if (n == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK) { // No data available yet printf("No data, doing other work...\n"); usleep(10000); continue; } else { perror("read"); break; } } else if (n == 0) { // EOF break; } else { // Data received printf("Read %zd bytes\n", n); } } close(fd); }

4.2 epoll Event Loop

#include <sys/epoll.h> #include <sys/socket.h> #include <netinet/in.h> #define MAX_EVENTS 100 void epoll_server_example(int port) { int listen_fd = socket(AF_INET, SOCK_STREAM, 0); if (listen_fd == -1) return; // Set socket options int opt = 1; setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); // Bind struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = INADDR_ANY; if (bind(listen_fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) { perror("bind"); close(listen_fd); return; } // Listen if (listen(listen_fd, 10) == -1) { perror("listen"); close(listen_fd); return; } // Create epoll instance int epoll_fd = epoll_create1(0); if (epoll_fd == -1) { perror("epoll_create1"); close(listen_fd); return; } // Add listen socket to epoll struct epoll_event ev; ev.events = EPOLLIN; ev.data.fd = listen_fd; if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, listen_fd, &ev) == -1) { perror("epoll_ctl"); close(epoll_fd); close(listen_fd); return; } struct epoll_event events[MAX_EVENTS]; while (1) { int nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1); if (nfds == -1) { perror("epoll_wait"); break; } for (int i = 0; i < nfds; i++) { if (events[i].data.fd == listen_fd) { // New connection struct sockaddr_in client_addr; socklen_t client_len = sizeof(client_addr); int client_fd = accept(listen_fd, (struct sockaddr*)&client_addr, &client_len); if (client_fd == -1) { perror("accept"); continue; } // Set client socket non-blocking set_nonblocking(client_fd); // Add to epoll ev.events = EPOLLIN | EPOLLET; // Edge-triggered ev.data.fd = client_fd; if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_fd, &ev) == -1) { perror("epoll_ctl"); close(client_fd); } } else { // Data from client int client_fd = events[i].data.fd; char buffer[4096]; while (1) { ssize_t n = read(client_fd, buffer, sizeof(buffer)); if (n == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK) { // Done reading break; } else { perror("read"); close(client_fd); epoll_ctl(epoll_fd, EPOLL_CTL_DEL, client_fd, NULL); break; } } else if (n == 0) { // Client closed connection close(client_fd); epoll_ctl(epoll_fd, EPOLL_CTL_DEL, client_fd, NULL); break; } else { // Echo back write(client_fd, buffer, n); } } } } } close(epoll_fd); close(listen_fd); }

4.3 Edge-Triggered vs Level-Triggered

// Level-triggered (default) struct epoll_event ev; ev.events = EPOLLIN; // Level-triggered // Edge-triggered (more efficient, but requires careful handling) ev.events = EPOLLIN | EPOLLET; // Edge-triggered // Edge-triggered requires reading until EAGAIN void edge_triggered_handler(int fd) { char buffer[4096]; while (1) { ssize_t n = read(fd, buffer, sizeof(buffer)); if (n == -1) { if (errno == EAGAIN) { break; // Done reading } // Handle error break; } else if (n == 0) { // EOF break; } // Process data... } }

5. Advanced File Locking

5.1 Record Locking (fcntl)

#include <fcntl.h> int lock_record(int fd, off_t offset, off_t len, int type) { struct flock fl; fl.l_type = type; // F_RDLCK, F_WRLCK, F_UNLCK fl.l_whence = SEEK_SET; fl.l_start = offset; fl.l_len = len; fl.l_pid = getpid(); return fcntl(fd, F_SETLKW, &fl); // Blocking // return fcntl(fd, F_SETLK, &fl); // Non-blocking } void record_locking_example(void) { int fd = open("database.db", O_RDWR); if (fd == -1) return; // Lock a specific range of bytes if (lock_record(fd, 0, 100, F_WRLCK) == -1) { perror("lock_record"); close(fd); return; } // Critical section - bytes 0-99 are locked // ... // Unlock lock_record(fd, 0, 100, F_UNLCK); close(fd); }

5.2 Advisory vs Mandatory Locking

void demonstrate_advisory_locking(void) { int fd = open("data.txt", O_RDWR); if (fd == -1) return; struct flock fl = { .l_type = F_WRLCK, .l_whence = SEEK_SET, .l_start = 0, .l_len = 0, // 0 means lock to EOF .l_pid = getpid() }; // Advisory lock (default) if (fcntl(fd, F_SETLK, &fl) == 0) { printf("Advisory lock acquired\n"); // Other processes can still access the file // unless they also check the lock } // For mandatory locking, mount filesystem with 'mand' option // and set setgid bit without execute permission close(fd); }

6. Direct I/O (O_DIRECT)

6.1 Bypassing Page Cache

#include <fcntl.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #define ALIGNMENT 4096 void* aligned_alloc_direct(size_t size) { void *ptr; if (posix_memalign(&ptr, ALIGNMENT, size) != 0) { return NULL; } return ptr; } void direct_io_example(void) { int fd = open("direct_io.dat", O_RDWR | O_CREAT | O_DIRECT, 0644); if (fd == -1) { perror("open (O_DIRECT may not be supported)"); return; } size_t size = ALIGNMENT * 10; // Must be aligned char *buffer = aligned_alloc_direct(size); if (!buffer) { close(fd); return; } // Fill buffer memset(buffer, 'A', size); // Write directly to disk (bypasses page cache) ssize_t nwritten = write(fd, buffer, size); if (nwritten == -1) { perror("write"); } else { printf("Wrote %zd bytes directly to disk\n", nwritten); } // Read directly from disk lseek(fd, 0, SEEK_SET); char *read_buf = aligned_alloc_direct(size); if (read_buf) { ssize_t nread = read(fd, read_buf, size); if (nread > 0) { printf("Read %zd bytes directly from disk\n", nread); } free(read_buf); } free(buffer); close(fd); }

6.2 Direct I/O with Alignment Requirements

#include <sys/stat.h> #include <unistd.h> size_t get_block_size(int fd) { struct stat st; if (fstat(fd, &st) == -1) { return 4096; // Default } return st.st_blksize; } void check_alignment_requirements(int fd) { size_t blk_size = get_block_size(fd); printf("Block size: %zu bytes\n", blk_size); printf("Alignment required: %zu\n", blk_size); printf("Offset alignment required: %zu\n", blk_size); printf("Buffer alignment required: %zu\n", blk_size); // Verify alignment void *buffer; if (posix_memalign(&buffer, blk_size, blk_size * 10) == 0) { printf("Buffer properly aligned\n"); free(buffer); } }

7. Splice and Zero-Copy I/O

7.1 splice() for File-to-File Copy

#include <fcntl.h> #include <unistd.h> int splice_copy(const char *src, const char *dst) { int fd_in = open(src, O_RDONLY); if (fd_in == -1) return -1; int fd_out = open(dst, O_WRONLY | O_CREAT | O_TRUNC, 0644); if (fd_out == -1) { close(fd_in); return -1; } // Get file size off_t size = lseek(fd_in, 0, SEEK_END); lseek(fd_in, 0, SEEK_SET); off_t copied = 0; while (copied < size) { ssize_t n = splice(fd_in, NULL, fd_out, NULL, size - copied, SPLICE_F_MOVE); if (n <= 0) { close(fd_in); close(fd_out); return -1; } copied += n; } close(fd_in); close(fd_out); return 0; }

7.2 sendfile() for Network Transfers

#include <sys/sendfile.h> #include <sys/socket.h> void sendfile_example(int client_fd, const char *filename) { int file_fd = open(filename, O_RDONLY); if (file_fd == -1) return; struct stat st; fstat(file_fd, &st); off_t size = st.st_size; off_t offset = 0; // Zero-copy transfer from file to socket ssize_t sent = sendfile(client_fd, file_fd, &offset, size); if (sent == -1) { perror("sendfile"); } else { printf("Sent %zd bytes\n", sent); } close(file_fd); }

8. Advanced Buffering Strategies

8.1 Custom Buffer Management

#include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct { char *buffer; size_t size; size_t used; size_t position; int fd; int error; } Buffer; Buffer* create_buffer(size_t size, int fd) { Buffer *buf = malloc(sizeof(Buffer)); buf->buffer = malloc(size); buf->size = size; buf->used = 0; buf->position = 0; buf->fd = fd; buf->error = 0; return buf; } int buffer_write(Buffer *buf, const char *data, size_t len) { size_t remaining = buf->size - buf->used; if (len > remaining) { // Flush buffer if (buf->used > 0) { ssize_t written = write(buf->fd, buf->buffer, buf->used); if (written != (ssize_t)buf->used) { buf->error = 1; return -1; } buf->used = 0; } // Write large data directly if (len > buf->size) { ssize_t written = write(buf->fd, data, len); return written; } } // Copy to buffer memcpy(buf->buffer + buf->used, data, len); buf->used += len; return len; } int buffer_flush(Buffer *buf) { if (buf->used == 0) return 0; ssize_t written = write(buf->fd, buf->buffer, buf->used); if (written != (ssize_t)buf->used) { buf->error = 1; return -1; } buf->used = 0; return 0; }

8.2 Double Buffering for Overlap

#include <pthread.h> #include <semaphore.h> typedef struct { char *buffer1; char *buffer2; size_t size; int active_buffer; int reading; int processing; sem_t read_sem; sem_t process_sem; pthread_mutex_t mutex; } DoubleBuffer; DoubleBuffer* create_double_buffer(size_t size) { DoubleBuffer *db = malloc(sizeof(DoubleBuffer)); db->buffer1 = malloc(size); db->buffer2 = malloc(size); db->size = size; db->active_buffer = 0; db->reading = 0; db->processing = 0; sem_init(&db->read_sem, 0, 1); sem_init(&db->process_sem, 0, 0); pthread_mutex_init(&db->mutex, NULL); return db; } void* reader_thread(void *arg) { DoubleBuffer *db = arg; int fd = *(int*)((void**)arg + 1); while (1) { sem_wait(&db->read_sem); char *buffer = db->active_buffer ? db->buffer2 : db->buffer1; ssize_t n = read(fd, buffer, db->size); if (n <= 0) break; pthread_mutex_lock(&db->mutex); db->reading = n; db->active_buffer = !db->active_buffer; pthread_mutex_unlock(&db->mutex); sem_post(&db->process_sem); } return NULL; } void* processor_thread(void *arg) { DoubleBuffer *db = arg; while (1) { sem_wait(&db->process_sem); pthread_mutex_lock(&db->mutex); char *buffer = db->active_buffer ? db->buffer2 : db->buffer1; int size = db->reading; pthread_mutex_unlock(&db->mutex); if (size == 0) break; // Process buffer for (int i = 0; i < size; i++) { buffer[i] = toupper(buffer[i]); } // Write processed data write(1, buffer, size); sem_post(&db->read_sem); } return NULL; }

9. I/O Performance Tuning

9.1 File System Optimization

#include <fcntl.h> #include <sys/statvfs.h> void tune_file_system(void) { // Get file system information struct statvfs stat; if (statvfs(".", &stat) == 0) { printf("Block size: %lu\n", stat.f_bsize); printf("Fragment size: %lu\n", stat.f_frsize); printf("Total blocks: %lu\n", stat.f_blocks); printf("Free blocks: %lu\n", stat.f_bfree); } // Set file access hints int fd = open("data.bin", O_RDWR | O_CREAT, 0644); // Posix fadvise #ifdef __linux__ posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL); // Sequential access posix_fadvise(fd, 0, 0, POSIX_FADV_WILLNEED); // Prefetch posix_fadvise(fd, 0, 0, POSIX_FADV_NOREUSE); // One-time use #endif // Sync file data fdatasync(fd); // Sync data, not metadata fsync(fd); // Sync data and metadata close(fd); }

9.2 I/O Scheduling

#include <sys/ioctl.h> #include <linux/fs.h> void set_io_scheduler(const char *device, const char *scheduler) { int fd = open(device, O_RDONLY); if (fd == -1) return; // Write scheduler to sysfs char path[256]; snprintf(path, sizeof(path), "/sys/block/%s/queue/scheduler", device); FILE *f = fopen(path, "w"); if (f) { fprintf(f, "%s", scheduler); fclose(f); } // Get current settings struct stat st; if (fstat(fd, &st) == 0) { printf("Device: %s\n", device); printf("Block size: %lu\n", st.st_blksize); } close(fd); }

10. Complete Example: High-Performance Logging System

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <unistd.h> #include <pthread.h> #include <sys/mman.h> #include <time.h> #define LOG_BUFFER_SIZE (1024 * 1024) // 1 MB #define LOG_FILE_SIZE (100 * 1024 * 1024) // 100 MB typedef struct { int fd; char *buffer; size_t buffer_pos; size_t buffer_size; pthread_mutex_t lock; volatile int running; pthread_t flush_thread; } AsyncLogger; AsyncLogger* logger_create(const char *filename) { AsyncLogger *logger = malloc(sizeof(AsyncLogger)); logger->fd = open(filename, O_WRONLY | O_CREAT | O_APPEND, 0644); if (logger->fd == -1) { free(logger); return NULL; } // Set large buffer for better performance if (posix_fadvise(logger->fd, 0, 0, POSIX_FADV_SEQUENTIAL) != 0) { // Ignore errors } logger->buffer = malloc(LOG_BUFFER_SIZE); logger->buffer_pos = 0; logger->buffer_size = LOG_BUFFER_SIZE; logger->running = 1; pthread_mutex_init(&logger->lock, NULL); return logger; } void logger_log(AsyncLogger *logger, const char *format, ...) { pthread_mutex_lock(&logger->lock); // Format message va_list args; va_start(args, format); int needed = vsnprintf(NULL, 0, format, args); va_end(args); if (logger->buffer_pos + needed + 1 >= logger->buffer_size) { // Flush buffer ssize_t written = write(logger->fd, logger->buffer, logger->buffer_pos); if (written > 0) { logger->buffer_pos = 0; } } // Write to buffer va_start(args, format); vsnprintf(logger->buffer + logger->buffer_pos, logger->buffer_size - logger->buffer_pos, format, args); va_end(args); logger->buffer_pos += needed; logger->buffer[logger->buffer_pos++] = '\n'; pthread_mutex_unlock(&logger->lock); } void* flush_thread(void *arg) { AsyncLogger *logger = arg; while (logger->running) { usleep(100000); // 100 ms pthread_mutex_lock(&logger->lock); if (logger->buffer_pos > 0) { ssize_t written = write(logger->fd, logger->buffer, logger->buffer_pos); if (written > 0) { logger->buffer_pos = 0; } } pthread_mutex_unlock(&logger->lock); } return NULL; } void logger_start(AsyncLogger *logger) { pthread_create(&logger->flush_thread, NULL, flush_thread, logger); } void logger_destroy(AsyncLogger *logger) { logger->running = 0; pthread_join(logger->flush_thread, NULL); // Final flush if (logger->buffer_pos > 0) { write(logger->fd, logger->buffer, logger->buffer_pos); } close(logger->fd); free(logger->buffer); pthread_mutex_destroy(&logger->lock); free(logger); } int main() { AsyncLogger *logger = logger_create("app.log"); if (!logger) { perror("Failed to create logger"); return 1; } logger_start(logger); // Log messages for (int i = 0; i < 1000000; i++) { logger_log(logger, "Iteration %d: timestamp = %lld", i, (long long)time(NULL)); } logger_destroy(logger); return 0; }

Conclusion

Advanced I/O operations in C provide powerful tools for building high-performance applications. From memory-mapped files for efficient large-file access to scatter-gather I/O for reducing system calls, from asynchronous I/O for non-blocking operations to zero-copy techniques for maximum throughput—mastering these techniques is essential for serious systems programming.

Key takeaways:

  • Memory mapping provides the fastest random access to files
  • Scatter-gather I/O reduces system call overhead
  • Asynchronous I/O enables concurrent I/O operations
  • epoll scales to thousands of connections
  • Direct I/O bypasses the page cache for predictable latency
  • Splice/sendfile achieve zero-copy data movement
  • Proper buffering dramatically improves performance

Choose the right technique based on your application's needs:

  • For databases: mmap + direct I/O
  • For web servers: epoll + sendfile
  • For logging: buffered async I/O
  • For data processing: scatter-gather + vectorized operations

The examples in this guide provide a foundation for implementing production-ready I/O systems. Always benchmark your specific use case, as the optimal approach depends on hardware, operating system, and workload characteristics.

Complete C Programming Guide + Compilers Collection


1. C srand() Function – Understanding Seed Initialization

https://macronepal.com/understanding-the-c-srand-function
Explains how srand() initializes the pseudo-random number generator in C by setting a seed value. Using the same seed produces the same sequence, while time(NULL) gives different results each run.


2. C rand() Function Mechanics and Limitations

https://macronepal.com/c-rand-function-mechanics-and-limitations
Explains how rand() generates pseudo-random numbers between 0 and RAND_MAX, its deterministic nature, and limitations for security use cases.


3. C log() Function

https://macronepal.com/c-log-function-2
Covers natural logarithm calculation using <math.h> and its applications.


4. Mastering Date and Time in C

https://macronepal.com/mastering-date-and-time-in-c
Explains <time.h> functions like time(), clock(), difftime(), and struct tm.


5. Mastering time_t Type in C

https://macronepal.com/mastering-the-c-time_t-type-for-time-management
Explains time representation as seconds since Unix epoch and conversion functions.


6. C exp() Function

https://macronepal.com/c-exp-function-mechanics-and-implementation
Explains exponential function exp(x) and its scientific applications.


7. C log() Function (Alternate Guide)

https://macronepal.com/c-log-function
Comparison of log() and log10() with usage examples.


8. C log10() Function

https://macronepal.com/mastering-the-log10-function-in-c
Explains base-10 logarithm for engineering and scientific applications.


9. C tan() Function

https://macronepal.com/understanding-the-c-tan-function
Explains tangent function and radian-based calculations.


10. Random Numbers in C (Secure vs Predictable)

https://macronepal.com/mastering-c-random-numbers-for-secure-and-predictable-applications
Explains difference between rand() and secure randomness methods.


11. Free Online C Compiler

https://macronepal.com/free-online-c-code-compiler-2
Browser-based compiler for testing C programs instantly.


C Functions, Arguments, Parameters & Flow

Mastering Functions in C – Complete Guide

https://macronepal.com/c/mastering-functions-in-c-a-complete-guide/
Covers function structure, modular programming, and real-world usage.


Function Arguments in C

https://macronepal.com/c-function-arguments/
Explains how arguments are passed and used in function calls.


Function Parameters in C

https://macronepal.com/c-function-parameters/
Explains defining inputs for functions and matching them with arguments.


Function Declarations in C

https://macronepal.com/c-function-declarations-syntax-rules-and-best-practices/
Covers prototypes, syntax rules, and best practices.


Function Calls in C

https://macronepal.com/understanding-function-calls-in-c-syntax-mechanics-and-best-practices/
Explains execution flow and parameter handling during function calls.


Void Functions in C

https://macronepal.com/understanding-void-functions-in-c-syntax-patterns-and-best-practices/
Explains functions that do not return values.


Return Values in C

https://macronepal.com/c-return-values-mechanics-types-and-best-practices/
Explains different return types and how functions return results.


Pass-by-Value in C

https://macronepal.com/aws/understanding-pass-by-value-in-c-mechanics-implications-and-best-practices/
Explains how copies of variables are passed into functions.


Pass-by-Reference in C

https://macronepal.com/c/understanding-pass-by-reference-in-c-pointers-semantics-and-safe-practices/
Explains using pointers to modify original variables.


C strstr() Function

https://macronepal.com/aws/c-strstr-function/
Explains substring search inside strings in C.


C Preprocessor & Macros

https://macronepal.com/mastering-c-variadic-macros-for-flexible-debugging/
https://macronepal.com/mastering-the-stdc-macro-in-c/
https://macronepal.com/c-time-macro-mechanics-and-usage/
https://macronepal.com/understanding-the-c-date-macro/
https://macronepal.com/c-file-type/
https://macronepal.com/mastering-c-line-macro-for-debugging-and-diagnostics/
https://macronepal.com/mastering-predefined-macros-in-c/
https://macronepal.com/c-error-directive-mechanics-and-usage/
https://macronepal.com/understanding-the-c-pragma-directive/
https://macronepal.com/c-include-directive/


C Structures, Memory, Scope & Linkage

https://macronepal.com/mastering-structures-in-c/
https://macronepal.com/c-structure-declaration-mechanics-and-usage/
https://macronepal.com/c-structure-initialization-mechanics-and-best-practices/
https://macronepal.com/mastering-c-structure-member-access-for-reliable-data-handling/
https://macronepal.com/c-nested-structures/
https://macronepal.com/mastering-arrays-of-structures-in-c/
https://macronepal.com/c-structure-pointers-mechanics-and-implementation/
https://macronepal.com/understanding-c-structure-parameter-passing-mechanics/
https://macronepal.com/mastering-c-returning-structures-for-efficient-data-flow/
https://macronepal.com/c-self-referential-structures/
https://macronepal.com/mastering-structure-alignment-in-c/
https://macronepal.com/c-structure-padding-mechanics-and-optimization/
https://macronepal.com/understanding-c-flexible-array-members-mechanics-and-usage/
https://macronepal.com/mastering-c-anonymous-structures-for-flattened-data-layouts/
https://macronepal.com/c-unions/
https://macronepal.com/mastering-c-name-mangling-and-symbol-decoration/
https://macronepal.com/c-no-linkage-mechanics-and-scope-isolation/
https://macronepal.com/understanding-c-internal-linkage-mechanics-and-architecture/


C Scope, Storage Classes & Typedef

https://macronepal.com/mastering-function-prototype-scope-in-c/
https://macronepal.com/c-function-scope-mechanics-and-visibility/
https://macronepal.com/understanding-c-file-scope-mechanics-and-architecture/
https://macronepal.com/mastering-c-scope-rules-for-predictable-name-resolution/
https://macronepal.com/c-scope-rules/
https://macronepal.com/mastering-c-register-storage-class-for-historical-context-and-modern-alternatives/
https://macronepal.com/mastering-_thread_local-in-c/
https://macronepal.com/c-extern-storage-class-mechanics-and-usage/
https://macronepal.com/understanding-the-c-static-storage-class-mechanics-and-usage/
https://macronepal.com/c-auto-storage-class/
https://macronepal.com/c-typedef-with-pointers/


Extra Articles

https://macronepal.com/13757-2/
https://macronepal.com/13748-2/
https://macronepal.com/13747-2/
https://macronepal.com/13746-2/
https://macronepal.com/13745-2/
https://macronepal.com/13708-2/
https://macronepal.com/13707-2/
https://macronepal.com/13702-2/


Online Compilers

https://macronepal.com/free-html-online-code-compiler/
https://macronepal.com/free-online-python-code-compiler/
https://macronepal.com/free-online-python2-code-compiler/
https://macronepal.com/free-online-java-code-compiler/
https://macronepal.com/free-online-javascript-code-compiler/
https://macronepal.com/free-online-node-js-code-compiler/
https://macronepal.com/free-online-c-code-compiler/
https://macronepal.com/free-online-c-code-compiler-2/
https://macronepal.com/free-online-c-code-compiler-3/
https://macronepal.com/free-online-php-code-compiler/
https://macronepal.com/free-online-ruby-code-compiler/
https://macronepal.com/free-online-perl-code-compiler/
https://macronepal.com/free-online-lua-code-compiler/
https://macronepal.com/free-online-tcl-code-compiler/
https://macronepal.com/free-online-groovy-code-compiler/
https://macronepal.com/free-online-j-shell-code-compiler/
https://macronepal.com/free-online-haskell-code-compiler/
https://macronepal.com/free-online-scala-code-compiler/
https://macronepal.com/free-online-common-lisp-code-compiler/
https://macronepal.com/free-online-d-code-compiler/
https://macronepal.com/free-online-ada-code-compiler/
https://macronepal.com/free-erlang-code-compiler/
https://macronepal.com/free-online-assembly-code-compiler/

Building Blocks of C: A Complete Guide to Functions
Explains how functions work in C programming, including function declaration, definition, parameters, return values, and how functions help organize reusable code.
https://macronepal.com/bash/building-blocks-of-c-a-complete-guide-to-functions/

The Heart of Text Processing: A Complete Guide to Strings in C
Explains how strings are used in C, covering character arrays, string handling functions, and common techniques for text processing tasks.
https://macronepal.com/bash/the-heart-of-text-processing-a-complete-guide-to-strings-in-c-2/

The Cornerstone of Data Organization: A Complete Guide to Arrays in C
Describes how arrays store multiple values in C, including indexing, initialization, and using arrays to manage structured data efficiently.
https://macronepal.com/bash/the-cornerstone-of-data-organization-a-complete-guide-to-arrays-in-c/

Guaranteed Execution: A Complete Guide to the Do-While Loop in C
Explains the do-while loop structure in C, highlighting how it ensures code runs at least once before checking the loop condition.
https://macronepal.com/bash/guaranteed-execution-a-complete-guide-to-the-do-while-loop-in-c/

Mastering Iteration: A Complete Guide to the For Loop in C
Explains how the for loop works in C, including initialization, condition checking, and increment steps for repeated execution of code blocks.
https://macronepal.com/bash/mastering-iteration-a-complete-guide-to-the-for-loop-in-c/

Mastering Iteration: A Complete Guide to While Loops in C
Explains the while loop structure in C, focusing on condition-based repetition and proper loop control techniques.
https://macronepal.com/bash/mastering-iteration-a-complete-guide-to-while-loops-in-c/

Beyond If-Else: A Complete Guide to Switch Case in C
Explains how switch-case statements work in C programming, enabling efficient handling of multiple conditional branches.
https://macronepal.com/bash/beyond-if-else-a-complete-guide-to-switch-case-in-c/

Mastering the Fundamentals: A Complete Guide to Arithmetic Operations in C
Explains how arithmetic operators such as addition, subtraction, multiplication, and division work in C, along with operator precedence and usage examples.
https://macronepal.com/bash/mastering-the-fundamentals-a-complete-guide-to-arithmetic-operations-in-c/

Foundation of C Programming: A Complete Guide to Basic Input Output
Explains how input and output functions like printf and scanf work in C, forming the foundation for interacting with users and displaying program results.
https://macronepal.com/bash/foundation-of-c-programming-a-complete-guide-to-basic-input-output/

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper