You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在主服务器与代理服务器间实现进程级互斥锁及条件变量

Alright, let's get your mainserver-proxy shared memory setup properly synchronized with mutexes and condition variables! The key here is to coordinate their actions so the proxy doesn't overwrite data while the mainserver is reading, and the mainserver doesn't waste CPU cycles polling for new filenames. Here's a step-by-step implementation tailored to your workflow:

Core Synchronization Design

We'll use POSIX pthread mutexes and condition variables configured for inter-process sharing. The setup needs two condition variables:

  • One for the proxy to signal the mainserver when a new filename is ready
  • One for the mainserver to signal the proxy when the file content is available

Plus a mutex to protect all shared state from race conditions.

Shared Memory Structure

First, define a struct that holds both your data and synchronization primitives. This lives entirely in shared memory so both processes can access it:

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#define SHM_NAME "/my_shared_memory"
#define MAX_FILENAME_LEN 256
#define MAX_CONTENT_SIZE 4096

// Shared data structure with synchronization primitives
typedef struct {
    pthread_mutex_t mutex;
    pthread_cond_t cond_proxy_to_main;  // Proxy → Mainserver: New filename ready
    pthread_cond_t cond_main_to_proxy;  // Mainserver → Proxy: Content ready
    char filename[MAX_FILENAME_LEN];
    char file_content[MAX_CONTENT_SIZE];
    int has_new_filename;  // Flag: 1 if proxy wrote a new filename
    int content_ready;     // Flag: 1 if mainserver loaded content
    int is_initialized;    // Flag: 1 if sync primitives are set up
} SharedData;

Proxy Server Code

This is the process that writes filenames and reads the resulting content:

int main() {
    // Create/open shared memory
    int shm_fd = shm_open(SHM_NAME, O_CREAT | O_RDWR, 0666);
    if (shm_fd == -1) { perror("shm_open failed"); exit(EXIT_FAILURE); }
    ftruncate(shm_fd, sizeof(SharedData));
    
    SharedData* shared_data = mmap(NULL, sizeof(SharedData), PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
    if (shared_data == MAP_FAILED) { perror("mmap failed"); exit(EXIT_FAILURE); }

    // Initialize sync primitives (only once, first process to start does this)
    if (!shared_data->is_initialized) {
        pthread_mutexattr_t mutex_attr;
        pthread_mutexattr_init(&mutex_attr);
        pthread_mutexattr_setpshared(&mutex_attr, PTHREAD_PROCESS_SHARED);
        pthread_mutex_init(&shared_data->mutex, &mutex_attr);
        pthread_mutexattr_destroy(&mutex_attr);

        pthread_condattr_t cond_attr;
        pthread_condattr_init(&cond_attr);
        pthread_condattr_setpshared(&cond_attr, PTHREAD_PROCESS_SHARED);
        pthread_cond_init(&shared_data->cond_proxy_to_main, &cond_attr);
        pthread_cond_init(&shared_data->cond_main_to_proxy, &cond_attr);
        pthread_condattr_destroy(&cond_attr);

        shared_data->is_initialized = 1;
        shared_data->has_new_filename = 0;
        shared_data->content_ready = 1; // Start ready for first filename
    }

    // Example workflow: Send a filename and wait for content
    const char* target_file = "example.txt";
    pthread_mutex_lock(&shared_data->mutex);

    // Wait for previous content to be processed (if any)
    while (!shared_data->content_ready) {
        pthread_cond_wait(&shared_data->cond_main_to_proxy, &shared_data->mutex);
    }
    shared_data->content_ready = 0;

    // Write the new filename
    strncpy(shared_data->filename, target_file, MAX_FILENAME_LEN - 1);
    shared_data->filename[MAX_FILENAME_LEN - 1] = '\0';
    shared_data->has_new_filename = 1;

    // Signal mainserver to process the filename
    pthread_cond_signal(&shared_data->cond_proxy_to_main);

    // Wait for mainserver to load content
    while (!shared_data->content_ready) {
        pthread_cond_wait(&shared_data->cond_main_to_proxy, &shared_data->mutex);
    }

    // Read and use the content
    printf("Proxy received content:\n%s\n", shared_data->file_content);

    pthread_mutex_unlock(&shared_data->mutex);

    // Cleanup (optional, run when shutting down)
    // munmap(shared_data, sizeof(SharedData));
    // close(shm_fd);
    // shm_unlink(SHM_NAME);

    return 0;
}

Main Server Code

This is the process that reads filenames, loads content, and signals the proxy:

int main() {
    // Open existing shared memory (created by proxy)
    int shm_fd = shm_open(SHM_NAME, O_RDWR, 0666);
    if (shm_fd == -1) { perror("shm_open failed"); exit(EXIT_FAILURE); }
    
    SharedData* shared_data = mmap(NULL, sizeof(SharedData), PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
    if (shared_data == MAP_FAILED) { perror("mmap failed"); exit(EXIT_FAILURE); }

    // Ensure sync primitives are initialized
    if (!shared_data->is_initialized) {
        perror("Shared memory not initialized by proxy");
        exit(EXIT_FAILURE);
    }

    // Continuous loop to process filenames
    while (1) {
        pthread_mutex_lock(&shared_data->mutex);

        // Wait for proxy to send a new filename
        while (!shared_data->has_new_filename) {
            pthread_cond_wait(&shared_data->cond_proxy_to_main, &shared_data->mutex);
        }

        // Load file content into shared memory
        FILE* fp = fopen(shared_data->filename, "r");
        if (fp != NULL) {
            memset(shared_data->file_content, 0, MAX_CONTENT_SIZE);
            fread(shared_data->file_content, 1, MAX_CONTENT_SIZE - 1, fp);
            fclose(fp);
        } else {
            strcpy(shared_data->file_content, "Error: File not found or unreadable");
        }

        // Update state and signal proxy
        shared_data->has_new_filename = 0;
        shared_data->content_ready = 1;
        pthread_cond_signal(&shared_data->cond_main_to_proxy);

        pthread_mutex_unlock(&shared_data->mutex);
    }

    // Cleanup (run if loop exits)
    // pthread_mutex_destroy(&shared_data->mutex);
    // pthread_cond_destroy(&shared_data->cond_proxy_to_main);
    // pthread_cond_destroy(&shared_data->cond_main_to_proxy);
    // munmap(shared_data, sizeof(SharedData));
    // close(shm_fd);

    return 0;
}

Key Notes to Remember

  • Process-Shared Attributes: The PTHREAD_PROCESS_SHARED flag is critical—without it, mutexes/cond vars only work within a single process.
  • Loop Conditions: Always use while (not if) when waiting on condition variables. This handles "spurious wakeups" (unexpected wakeups that don't mean your condition is met).
  • Initialization Guard: The is_initialized flag prevents multiple processes from re-initializing sync primitives, which causes undefined behavior.
  • Error Handling: I added basic error checking here, but in production code, you should validate every system call return value (e.g., pthread_mutex_lock can fail!).
  • Cleanup: Don't forget to unmap shared memory and unlink it when your processes shut down to avoid leftover resources.

内容的提问来源于stack exchange,提问作者cranberry

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 09:09:06