MST

星途 面试题库

面试题:C语言命名管道并发访问中的同步问题及解决

在使用C语言进行Linux命名管道的并发访问时,会遇到哪些同步相关的问题?请举例说明,并阐述你将如何通过代码手段解决这些同步问题,如使用信号量或互斥锁等机制。
12.1万 热度难度
编程语言C

知识考点

AI 面试

面试题答案

一键面试

可能遇到的同步问题

  1. 数据竞争:多个进程同时对命名管道进行读写操作时,可能导致数据混乱。例如,一个进程正在写入数据,另一个进程同时读取,可能读到不完整的数据。
  2. 进程饥饿:如果没有合适的同步机制,某些进程可能长时间无法获取对命名管道的访问权,导致饥饿现象。

示例说明

假设我们有两个进程,一个进程(进程A)向命名管道写入数据,另一个进程(进程B)从命名管道读取数据。如果没有同步机制,可能会出现以下情况:

// 进程A
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

int main() {
    int fd = open("mypipe", O_WRONLY);
    if (fd == -1) {
        perror("open");
        return 1;
    }
    const char *msg = "Hello, world!";
    write(fd, msg, strlen(msg));
    close(fd);
    return 0;
}

// 进程B
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

int main() {
    int fd = open("mypipe", O_RDONLY);
    if (fd == -1) {
        perror("open");
        return 1;
    }
    char buf[100];
    read(fd, buf, sizeof(buf));
    printf("Read: %s\n", buf);
    close(fd);
    return 0;
}

在没有同步的情况下,进程B可能读到不完整的消息。

使用信号量解决同步问题

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <semaphore.h>

#define SEM_NAME "/mypipe_sem"

int main() {
    sem_t *sem = sem_open(SEM_NAME, O_CREAT, 0666, 1);
    if (sem == SEM_FAILED) {
        perror("sem_open");
        return 1;
    }

    int fd = open("mypipe", O_WRONLY);
    if (fd == -1) {
        perror("open");
        sem_close(sem);
        sem_unlink(SEM_NAME);
        return 1;
    }

    sem_wait(sem);
    const char *msg = "Hello, world!";
    write(fd, msg, strlen(msg));
    sem_post(sem);

    close(fd);
    sem_close(sem);
    sem_unlink(SEM_NAME);
    return 0;
}
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <semaphore.h>

#define SEM_NAME "/mypipe_sem"

int main() {
    sem_t *sem = sem_open(SEM_NAME, 0);
    if (sem == SEM_FAILED) {
        perror("sem_open");
        return 1;
    }

    int fd = open("mypipe", O_RDONLY);
    if (fd == -1) {
        perror("open");
        sem_close(sem);
        return 1;
    }

    sem_wait(sem);
    char buf[100];
    read(fd, buf, sizeof(buf));
    printf("Read: %s\n", buf);
    sem_post(sem);

    close(fd);
    sem_close(sem);
    return 0;
}

在上述代码中,通过信号量 sem 来控制对命名管道的访问。写进程和读进程在访问命名管道前先 sem_wait 获取信号量,访问结束后 sem_post 释放信号量。

使用互斥锁解决同步问题

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

void *write_to_pipe(void *arg) {
    int fd = open("mypipe", O_WRONLY);
    if (fd == -1) {
        perror("open");
        return NULL;
    }

    pthread_mutex_lock(&mutex);
    const char *msg = "Hello, world!";
    write(fd, msg, strlen(msg));
    pthread_mutex_unlock(&mutex);

    close(fd);
    return NULL;
}

void *read_from_pipe(void *arg) {
    int fd = open("mypipe", O_RDONLY);
    if (fd == -1) {
        perror("open");
        return NULL;
    }

    pthread_mutex_lock(&mutex);
    char buf[100];
    read(fd, buf, sizeof(buf));
    printf("Read: %s\n", buf);
    pthread_mutex_unlock(&mutex);

    close(fd);
    return NULL;
}

int main() {
    pthread_t write_thread, read_thread;

    pthread_create(&write_thread, NULL, write_to_pipe, NULL);
    pthread_create(&read_thread, NULL, read_from_pipe, NULL);

    pthread_join(write_thread, NULL);
    pthread_join(read_thread, NULL);

    pthread_mutex_destroy(&mutex);
    return 0;
}

在这个使用互斥锁的例子中,通过 pthread_mutex_lockpthread_mutex_unlock 来保护对命名管道的访问,确保同一时间只有一个线程可以访问命名管道。