单读者写者(一个读者一个写者)问题为何要加锁

本文探讨了在单读者单写者问题中是否需要加锁的问题。虽然一个简单的例子表明在某些情况下可能不需要加锁,但当涉及到更复杂的场景,如线程间的操作同步时,加锁变得必要,以防止潜在的数据不一致性和程序崩溃。因此,即使是单个读者和单个写者,为了保证数据的正确性和系统的稳定性,仍需要进行互斥保护。
摘要由CSDN通过智能技术生成

http://bbs.csdn.net/topics/390248385 提出了一个问题:“一个线程读数据,一个线程写数据,要加锁?”并给出结论说不需要加锁。

不论作者水平如何,总会有很多人也都在想这个问题。

问题中给出了这样一个例子:

全局变量int g_val;

线程1

printf("%d",g_val);


线程2

g_val++;

在这个例子里,可以不加锁。因为这个g_val影响很小。

实际应用中,假设线程2每10秒执行一次,线程1作为显示线程2执行次数的计数器,每60秒执行一次,就可能出现线程2执行了11次,但是显示只有10次的情况。

次数多少可能不会造成重大影响。对例子做一定的修改如下:


int *g_val;

void Thread1()
{
    while(1)
    {
        //打印g_val数据
        printf("%d",*g_val);  //p1
        msleep(300);
    }
}

v
以下是C语言实现读者写者问题的代码,使用信号量机制: 引用:使用POSIX信号量机制解决读者-写者问题C语言实现,读者写者进程数量可设置。[^1] ```c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> #include <fcntl.h> #include <semaphore.h> #include <sys/mman.h> #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) // 全局变量 static sem_t *r_lock; // 读者锁 static sem_t *rw_lock; // 写者锁 static int *read_cnt; // 读者数量计数器 static int *data; // 共享数据区 // 读者线程 void *reader(void *arg) { int id = *(int *)arg; while (1) { // 读者加锁 sem_wait(r_lock); (*read_cnt)++; if (*read_cnt == 1) { sem_wait(rw_lock); } // 读者锁解锁 sem_post(r_lock); // 读取数据 printf("Reader %d is reading data: %d\n", id, *data); // 读者加锁 sem_wait(r_lock); (*read_cnt)--; if (*read_cnt == 0) { sem_post(rw_lock); } // 读者锁解锁 sem_post(r_lock); // 等待一段时间 sleep(rand() % 3 + 1); } return NULL; } // 写者线程 void *writer(void *arg) { int id = *(int *)arg; while (1) { // 写者加锁 sem_wait(rw_lock); // 写入数据 (*data)++; printf("Writer %d is writing data: %d\n", id, *data); // 写者锁解锁 sem_post(rw_lock); // 等待一段时间 sleep(rand() % 3 + 1); } return NULL; } int main(int argc, char *argv[]) { // 获取参数 if (argc != 3) { printf("usage: %s <reader_num> <writer_num>\n", argv); exit(1); } int reader_num = atoi(argv); int writer_num = atoi(argv); // 创建共享内存 int fd = shm_open("/shm", O_CREAT | O_RDWR, FILE_MODE); ftruncate(fd, sizeof(sem_t) * 2 + sizeof(int) * 2); r_lock = mmap(NULL, sizeof(sem_t), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); rw_lock = mmap(NULL, sizeof(sem_t), PROT_READ | PROT_WRITE, MAP_SHARED, fd, sizeof(sem_t)); read_cnt = mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, fd, sizeof(sem_t) * 2); data = mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, fd, sizeof(sem_t) * 2 + sizeof(int)); // 初始化信号量 sem_init(r_lock, 1, 1); sem_init(rw_lock, 1, 1); // 创建读者线程 pthread_t tid[reader_num + writer_num]; int index = 0; for (int i = 0; i < reader_num; i++) { int *id = malloc(sizeof(int)); *id = ++index; pthread_create(&tid[i], NULL, reader, id); } // 创建写者线程 for (int i = 0; i < writer_num; i++) { int *id = malloc(sizeof(int)); *id = ++index; pthread_create(&tid[reader_num + i], NULL, writer, id); } // 等待线程结束 for (int i = 0; i < reader_num + writer_num; i++) { pthread_join(tid[i], NULL); } // 销毁信号量 sem_destroy(r_lock); sem_destroy(rw_lock); // 删除共享内存 munmap(r_lock, sizeof(sem_t)); munmap(rw_lock, sizeof(sem_t)); munmap(read_cnt, sizeof(int)); munmap(data, sizeof(int)); shm_unlink("/shm"); return 0; } ``` 引用:使用System V信号量机制解决读者-写者问题C语言实现,读者写者进程数量可设置。 ```c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> #include <sys/sem.h> #include <sys/ipc.h> #include <sys/shm.h> #include <sys/types.h> // 定义信号量操作 static struct sembuf sem_r_lock = { {0, 0, SEM_UNDO}, {0, 1, SEM_UNDO}, }; static struct sembuf sem_r_unlock = { {0, -1, SEM_UNDO}, }; static struct sembuf sem_rw_lock = { {1, 0, SEM_UNDO}, {0, 0, SEM_UNDO}, }; static struct sembuf sem_rw_unlock = { {1, -1, SEM_UNDO}, }; // 全局变量 static int sem_id; // 信号量ID static int *read_cnt; // 读者数量计数器 static int *data; // 共享数据区 // 读者线程 void *reader(void *arg) { int id = *(int *)arg; while (1) { // 读者加锁 semop(sem_id, sem_r_lock, 2); (*read_cnt)++; if (*read_cnt == 1) { semop(sem_id, sem_rw_lock, 2); } // 读者锁解锁 semop(sem_id, sem_r_unlock, 1); // 读取数据 printf("Reader %d is reading data: %d\n", id, *data); // 读者加锁 semop(sem_id, sem_r_lock, 2); (*read_cnt)--; if (*read_cnt == 0) { semop(sem_id, sem_rw_unlock, 1); } // 读者锁解锁 semop(sem_id, sem_r_unlock, 1); // 等待一段时间 sleep(rand() % 3 + 1); } return NULL; } // 写者线程 void *writer(void *arg) { int id = *(int *)arg; while (1) { // 写者加锁 semop(sem_id, sem_rw_lock, 2); // 写入数据 (*data)++; printf("Writer %d is writing data: %d\n", id, *data); // 写者锁解锁 semop(sem_id, sem_rw_unlock, 1); // 等待一段时间 sleep(rand() % 3 + 1); } return NULL; } int main(int argc, char *argv[]) { // 获取参数 if (argc != 3) { printf("usage: %s <reader_num> <writer_num>\n", argv); exit(1); } int reader_num = atoi(argv); int writer_num = atoi(argv); // 创建共享内存 int shmid = shmget(IPC_PRIVATE, sizeof(int) * 2, IPC_CREAT | 0666); read_cnt = (int *)shmat(shmid, 0, 0); data = read_cnt + 1; // 初始化共享内存 *read_cnt = 0; *data = 0; // 创建信号量 sem_id = semget(IPC_PRIVATE, 2, IPC_CREAT | 0666); semctl(sem_id, 0, SETVAL, 1); semctl(sem_id, 1, SETVAL, 1); // 创建读者线程 pthread_t tid[reader_num + writer_num]; int index = 0; for (int i = 0; i < reader_num; i++) { int *id = malloc(sizeof(int)); *id = ++index; pthread_create(&tid[i], NULL, reader, id); } // 创建写者线程 for (int i = 0; i < writer_num; i++) { int *id = malloc(sizeof(int)); *id = ++index; pthread_create(&tid[reader_num + i], NULL, writer, id); } // 等待线程结束 for (int i = 0; i < reader_num + writer_num; i++) { pthread_join(tid[i], NULL); } // 删除信号量 semctl(sem_id, 0, IPC_RMID, 0); // 删除共享内存 shmdt(read_cnt); shmctl(shmid, IPC_RMID, 0); return 0; } ```
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值