面试题答案
一键面试可能遇到的同步问题
- 数据竞争:多个进程同时对命名管道进行读写操作时,可能导致数据混乱。例如,一个进程正在写入数据,另一个进程同时读取,可能读到不完整的数据。
- 进程饥饿:如果没有合适的同步机制,某些进程可能长时间无法获取对命名管道的访问权,导致饥饿现象。
示例说明
假设我们有两个进程,一个进程(进程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_lock
和 pthread_mutex_unlock
来保护对命名管道的访问,确保同一时间只有一个线程可以访问命名管道。