进程同步实验报告
|
1.实验名称 进程同步 |
|
(1) 编写程序,使用Linux操作系统中的信号量机制模拟实现生产者消费者问题。设有一个生产者和一个消费者,缓冲区可以存放产品,生产者不断生成产品放入缓冲区,消费者不断从缓冲区中取出产品,消费产品。 (2) 编写好一个C语言程序,在GCC中进行编译。 |
进程同步和互斥的基本概念 互斥(Mutex):确保多个进程或线程不会同时访问共享资源。互斥通常通过锁机制实现,当一个进程或线程获取了锁,其他进程或线程必须等待直到锁被释放。 同步(Synchronization):协调多个进程或线程的执行顺序,以确保它们在正确的时间执行正确的操作。同步机制可以确保进程或线程按照特定的顺序执行,或者在某些条件下等待其他进程或线程。 信号量(Semaphore):是一种同步机制,可以用来实现互斥和同步。信号量是一个整数变量,可以被进程或线程通过wait(P操作)和signal(V操作)来改变其值。 Linux进程同步原语 Linux提供了多种进程同步原语,包括互斥锁(mutexes)、读写锁(read-write locks)、条件变量(condition variables)、信号量(semaphores)等。这些原语可以帮助开发者在多线程或多进程环境下保护共享资源,避免竞态条件。 POSIX信号量#include<semaphore.h> POSIX信号量是由POSIX标准定义的,它提供了跨平台的线程和进程同步机制。POSIX信号量有两种形式: 无名信号量(Unnamed Semaphores): 无名信号量是在进程地址空间中创建的,它们只在创建它们的进程和任何随后继承它们的子进程中可见。无名信号量是通过sem_init函数创建的,并且在使用完毕后通过sem_destroy函数销毁。 无名信号量是轻量级的,因为它们不涉及内核和用户空间之间的上下文切换,适用于线程间同步。 有名信号量(Named Semaphores): 有名信号量是全局可见的,它们可以通过名称在不同进程间共享。有名信号量是通过sem_open函数创建的,并且可以在不同的程序之间共享。 有名信号量更重,因为它们需要在内核中维护,适用于不同进程间的同步。 信号量删除函数:sem_close(),sem_unlink() 信号量操作:sem_wait(),sem_trywait(),semtimedwait(),sem_post(),sem_getvalue() System V信号量#include<sys/sem.h> System V信号量是较旧的信号量机制,它是特定于UNIX系统的。 nt semget(key_t key,int num_sems,int sem_flags); int semctl(int sem_id,int sem_num,int cmd,union semun arg); int semop(int sem_id,struct sembuf *sops,size_t nsops); 使用步骤: ①使用semget()函数创建或获取信号量。不同进程通过使用同一个信号量键值来获得同一个信号量。 ②使用semctl()函数的SETVAL:操作初始化信号量。 ③使用sempop()函数进行信号量的PV操作,这是实现进程同步或互斥的核心工作。 ④如果不需要信号量,则从系统中删除它,此时使用shmctl()函数的IPC_RMID操作 信号量wait/signal原语 信号量是进程间或线程间同步的一种机制,它通过wait(P操作)和signal(V操作)两个原语来实现: wait(P操作):等待信号量。如果信号量的值大于0,wait操作会将其减1,然后继续执行。如果信号量的值为0,进程或线程将被阻塞,直到信号量的值变为正数。 signal(V操作):释放信号量。signal操作会将信号量的值增加1。如果有任何进程或线程因为等待该信号量而被阻塞,那么它们将被唤醒,并且其中一个(通常是FIFO顺序)将获得信号量,继续执行。 信号量的定义、赋初值及wait/signal操作 定义信号量:在Linux中,可以使用 <semaphore.h> 头文件中定义的 sem_t 类型来声明一个信号量。 sem_t sem; 初始化信号量:使用 sem_init 函数初始化信号量,并为其赋予一个初始值。 sem_init(&sem, 0, value); // value是信号量的初始值 wait操作(P操作):当进程或线程需要访问共享资源时,它会执行wait操作来减少信号量的值。 sem_wait(&sem); // 等同于sem_wait(&sem),因为sem_wait宏展开后就是P操作 signal操作(V操作):当进程或线程完成对共享资源的访问后,它会执行signal操作来增加信号量的值。 sem_post(&sem); // 等同于sem_post(&sem),因为sem_post宏展开后就是V操作 销毁信号量:当信号量不再需要时,应该使用 sem_destroy 函数来销毁它。 sem_destroy(&sem); 通过使用信号量,开发者可以控制对共享资源的访问,确保在任何时候只有一个进程或线程能够访问资源,或者按照特定的顺序访问资源,从而避免数据不一致和竞态条件。 |
|
5. 实验过程或源代码 #include <semaphore.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <pthread.h> #define MAX 256 //char buffer[MAX]; // 直接声明为固定大小的数组,避免动态分配内存 char *buffer;//可以用数组,可以用指针。 sem_t empty; // 定义同步信号量empty sem_t full; // 定义同步信号量full sem_t mutex; // 定义互斥信号量mutex void *producer(void *arg) // 生产者 { sem_wait(&empty); // empty的P操作 sem_wait(&mutex); // mutex的P操作 printf("input something to buffer: "); buffer = (char *)malloc(MAX); // 给缓冲区分配内存空间 fgets(buffer, MAX, stdin); // 输入产品至缓冲区 sem_post(&mutex); // mutex的V操作 sem_post(&full); // full的V操作 return NULL; } void *consumer(void *arg) // 消费者 { sem_wait(&full); // full的P操作 sem_wait(&mutex); // mutex的P操作 printf("read product from buffer: %s\n", buffer); // 从缓冲区取出产品 memset(buffer, 0, MAX); // 清空缓冲区 sem_post(&mutex); // mutex的V操作 sem_post(&empty); // empty的V操作 return NULL; } int main() { pthread_t producer_thread; pthread_t consumer_thread; int ret; sem_init(&empty, 0, 10); // 设置empty到初值为10 sem_init(&full, 0, 0); // 设置full到初值为0 sem_init(&mutex, 0, 1); // 设置mutex到初值为1 ret = pthread_create(&producer_thread, NULL, producer, NULL); // 创建生产者线程 ret = pthread_create(&consumer_thread, NULL, consumer, NULL); // 创建消费者线程 pthread_join(producer_thread, NULL); // 等待生产者线程结束 pthread_join(consumer_thread, NULL); // 等待消费者线程结束 sem_destroy(&empty); // 删除信号量 sem_destroy(&full); sem_destroy(&mutex); printf("The End...\n"); return 0; } |
编译代码文件,加上-lpthread,调用该库,之后运行。

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)