编写一个应用程序,要求包含3个进程,每个进程中包含2个线程,采用共享内存、套接字、信号量等通信方式实现进程间的通信、同步、互斥操作

这篇文档已经过时了,建议转到我主页中的另一篇文章《嵌入式系统原理与应用——基于Linux和ARM笔记整理》,里面有该题更详细的讲解

准备工作

导入库函数

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<string.h>
#include<unistd.h>
#include<pthread.h>  //线程调度
#include <sched.h> //进程调度
#include <sys/mman.h> //共享内存
#include <semaphore.h> //信号量
#include <sys/socket.h> //socket接口

声明所有线程函数

//declare call thread function
void *fun1(void *);
void *fun2(void *);
void *fun3(void *);
void *fun4(void *);
void *fun5(void *);
void *fun6(void *);

3个进程,每个进程中包含2个线程

	pid_t pid1,pid2,pid3;
	int ret;
        pid1=fork();
        printf("pid1:%d   ",getpid());
        printf("the return value:%d\n",pid1);
	pthread_t tid1,tid2;
	ret = pthread_create(&tid1,NULL,fun1,NULL);
	ret = pthread_create(&tid2,NULL,fun2,NULL);

        pid2=fork();
        printf("pid2:%d   ",getpid());
        printf("the return value:%d\n",pid2);
	pthread_t tid3,tid4;
	ret = pthread_create(&tid3,NULL,fun3,NULL);
	ret = pthread_create(&tid4,NULL,fun4,NULL);

        pid3=fork();
        printf("pid3:%d   ",getpid());
        printf("the return value:%d\n",pid3);
	pthread_t tid5,tid6;
	ret = pthread_create(&tid5,NULL,fun5,NULL);
	ret = pthread_create(&tid6,NULL,fun6,NULL);

每个线程函数的内部如下:

void *fun1(void *arg)
{
        printf("pthread_tid1 = %lu\n",(unsigned long)pthread_self());
	pthread_exit(NULL);
}
 
void *fun2(void *arg)
{
        printf("pthread_tid2 = %lu\n",(unsigned long)pthread_self());
	pthread_exit(NULL);
}
 
void *fun3(void *arg)
{
        printf("pthread_tid3 = %lu\n",(unsigned long)pthread_self());
	pthread_exit(NULL);
}
 
void *fun4(void *arg)
{
        printf("pthread_tid4 = %lu\n",(unsigned long)pthread_self());
	pthread_exit(NULL);
}
 
void *fun5(void *arg)
{
        printf("pthread_tid5 = %lu\n",(unsigned long)pthread_self());
	pthread_exit(NULL);
}
 
void *fun6(void *arg)
{
        printf("pthread_tid6 = %lu\n",(unsigned long)pthread_self());
	pthread_exit(NULL);
}

采用共享内存、套接字、信号量等通信方式实现进程间的通信、同步、互斥操作

互斥锁API

互斥量变量一般申请全局变量

pthread_mutex_t mutex;

int num=0; //公共临界变量

修改线程的函数,使fun1与fun2的线程使用互斥锁,即使用共享内存的形式进行同步

void *fun1(void *arg)
{
    pthread_mutex_lock(&mutex);  //加锁
    printf("pthread_tid1 = %lu\n",(unsigned long)pthread_self());
    sleep(1);  //休眠1s
    pthread_mutex_unlock(&mutex);  //解锁
	pthread_exit(NULL); //线程退出 可以使用pthread_join来回收资源
}
 
void *fun2(void *arg)
{
    pthread_mutex_lock(&mutex);  //加锁
    printf("pthread_tid2 = %lu\n",(unsigned long)pthread_self());
    sleep(2);  //休眠2s
    pthread_mutex_unlock(&mutex);  //解锁
    pthread_exit(NULL);
}

主函数最后回收所有资源,包括销毁互斥量操作

pthread_join(tid1,NULL);//阻塞回收线程 1
pthread_join(tid2,NULL);//阻塞回收线程 2
pthread_mutex_destroy(&mutex);//销毁互斥量

套接字

套接字主要用于进程间的通信

创建套接字对

    int sockfd[2];

    // 创建套接字对
    if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfd) == -1) {
        perror("socketpair");
        return 1;
    }

父(子)进程关闭子(父)进程的套接字

close(sockfd[1]); // 关闭父进程的套接字
// 子进程接收消息
close(sockfd[0]); // 关闭与父进程通信的套接字

close(sockfd[0]); // 关闭子进程的套接字
// 父进程发送消息给子进程
close(sockfd[1]); // 关闭与子进程通信的套接字

整合代码如下:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>

int main() {
    int sockfd[2];

    // 创建套接字对
    if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfd) == -1) {
        perror("socketpair");
        return 1;
    }

    pid_t pid = fork();

    if (pid == -1) {
        perror("fork");
        return 1;
    }

    if (pid == 0) {
        // 子进程
        close(sockfd[1]); // 关闭父进程的套接字

        printf("Child process (%d)\n", getpid());

        // 子进程接收消息
        char buf[256];
        ssize_t num_bytes = read(sockfd[0], buf, sizeof(buf));
        if (num_bytes == -1) {
            perror("read");
        } else {
            printf("Received message from parent: %s\n", buf);
        }

        close(sockfd[0]); // 关闭与父进程通信的套接字

        return 0;
    } 
    else {
        // 父进程
        close(sockfd[0]); // 关闭子进程的套接字

        printf("Parent process (%d)\n", getpid());

        // 父进程发送消息给子进程
        char msg[] = "Hello from parent process";
        ssize_t num_bytes = write(sockfd[1], msg, sizeof(msg));
        if (num_bytes == -1) {
            perror("write");
        }

        close(sockfd[1]); // 关闭与子进程通信的套接字

        return 0;
    }
}

运行结果

信号量

注意 互斥锁API 章节中的代码使用sleep函数勉强来控制线程的执行顺序,但这显然不是“长久之计”

信号量则可以帮助控制执行的顺序

申请信号量,一般都是全局变量

#define _GNU_SOURCE 
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <semaphore.h>

sem_t sem1,sem2,sem3;//申请的三个信号量变量

在主函数中初始化信号量,然后创建线程

	int ret;
	pthread_t tid1,tid2;
	ret = sem_init(&sem1,0,1);  //初始化信号量1 并且赋予其资源

相应地,为了使用信号量进行线程的同步,需要修改线程函数。

void *fun1(void *arg)
{
	sem_wait(&sem1);//因sem1本身有资源,所以不被阻塞 获取后sem1-1 下次会会阻塞
    printf("pthread_tid1 = %lu\n",(unsigned long)pthread_self());
	sem_post(&sem2);// 使得sem2获取到资源
	pthread_exit(NULL);
}

void *fun2(void *arg)
{
	sem_wait(&sem2);//因sem2在初始化时无资源会被阻塞,直至14行代码执行 不被阻塞 sem2-1 下次会阻塞
    printf("pthread_tid2 = %lu\n",(unsigned long)pthread_self());
	sem_post(&sem1);// 使得sem1获取到资源
	pthread_exit(NULL);
}

由此,更改sem_post里的参数地址,就可以实现控制线程执行顺序的目的

同样在主函数最后,需要回收线程资源和销毁信号量

	/*回收线程资源*/
	pthread_join(tid1,NULL);
	pthread_join(tid2,NULL);

	/*销毁信号量*/
	sem_destroy(&sem1);
	sem_destroy(&sem2);

简易版,只控制两个线程的代码整合如下:

#define _GNU_SOURCE 
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <semaphore.h>

sem_t sem1,sem2,sem3;//申请的三个信号量变量

void *fun1(void *arg)
{
	sem_wait(&sem1);//因sem1本身有资源,所以不被阻塞 获取后sem1-1 下次会会阻塞
    printf("pthread_tid1 = %lu\n",(unsigned long)pthread_self());
	sem_post(&sem2);// 使得sem2获取到资源
	pthread_exit(NULL);
}

void *fun2(void *arg)
{
	sem_wait(&sem2);//因sem2在初始化时无资源会被阻塞,直至14行代码执行 不被阻塞 sem2-1 下次会阻塞
    printf("pthread_tid2 = %lu\n",(unsigned long)pthread_self());
	sem_post(&sem1);// 使得sem1获取到资源
	pthread_exit(NULL);
}


int main(){
	int ret;
	pthread_t tid1,tid2;
	ret = sem_init(&sem1,0,1);  //初始化信号量1 并且赋予其资源
	ret = sem_init(&sem2,0,1);  //初始化信号量2 并且赋予其资源
	ret = sem_init(&sem3,0,1);  //初始化信号量1 并且赋予其资源


	ret = pthread_create(&tid1,NULL,fun1,NULL);
	ret = pthread_create(&tid2,NULL,fun2,NULL);

	/*回收线程资源*/
	pthread_join(tid1,NULL);
	pthread_join(tid2,NULL);

	/*销毁信号量*/
	sem_destroy(&sem1);
	sem_destroy(&sem2);

}

运行结果

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值