管道的通信

异步:多线程、多进程本质是异步执行

线程间同步机制:让多个线程在执行某个任务时,具有先后顺序的执行。

信号量:实现线程间同步。
操作步骤:
1. 定义信号量对象 :sem_t 
2. 初始化信号量 : sem_init();
3.申请信号量: P操作 :int sem_wait(sem_t *sem);
    释放信号量:V操作:int sem_post(sem_t *sem);
    PV操作
4. 销毁信号量:int sem_destroy(sem_t *sem);

int sem_init(sem_t *sem, int pshared, unsigned int value);
功能:初始化信号量
参数:
          sem:要初始化的信号量对象地址
          pshared:
                    0 : 线程间共享
                    非0 : 进程间共享
          value:信号量的初始值(初始资源数)
返回值:
      成功:0
      失败:-1

#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
char buff[1024] = {0};

sem_t sem1;
sem_t sem2;
sem_t sem3;

void *task1(void *arg)
{
	while (1)
	{
		sem_wait(&sem1);
	    fputs("A->", stdout);
       // fflush(stdout);
		sem_post(&sem2);
        sleep(1);
	}
}

void *task2(void *arg)
{
	while (1)
	{
        sem_wait(&sem2);
	    fputs("B->", stdout);
       // fflush(stdout);
	    //printf("buff = %s\n", buff);

		sem_post(&sem3);
        sleep(1);
	}
}
void *task3(void *arg)
{
	while (1)
	{
		sem_wait(&sem3);
	    fputs("C\n", stdout);
       // fflush(stdout);
	    //printf("buff = %s\n", buff);
		sem_post(&sem1);
        sleep(1);
	}
}

int main()
{
    pthread_t tid[3];

    sem_init(&sem1,0,1);
    sem_init(&sem2,0,0);
    sem_init(&sem3,0,0);

    pthread_create(&tid[0], NULL, task1, NULL);
	pthread_create(&tid[1], NULL, task2, NULL);
    pthread_create(&tid[2], NULL, task3, NULL);


	pthread_join(tid[0], NULL);
	pthread_join(tid[1], NULL);
    pthread_join(tid[2], NULL);

	sem_destroy(&sem1);
	sem_destroy(&sem2);
    sem_destroy(&sem3);

return 0;

}

互斥锁、信号量、读写锁、自旋锁----》锁

            死锁:死锁指的是在多线程环境中,每个执行流(线程)都有未释放的资源,
                       且互相请求对方未释放资源,从而导致陷入永久等待状态的情况。
        现象:
        现象1:忘记释放锁
        现象2:重复加锁
        现象3:多线程多锁,抢占锁资源不当
        如:线程A获取了1锁,线程B获取了2锁,同时线程A还想获取2锁,线程B还想获取1锁
        
        产生死锁的四个必要条件:
        (1) 互斥条件:一个资源每次只能被一个进程使用(一个执行流获取锁后,其它执行流不能再获取该锁)。
        (2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放(执行流本身使用着一把锁并不释放,还在请求别的锁)。
        (3) 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺(A执行流拿着锁,其它执行流不能释放)。
        (4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系(多个执行流拿着对方想要的锁,并且各执行流还去请求对方的锁)。

解决方法:
        1.锁一定要成对出现
        2.使线程的加锁顺序一致
        3.破坏环路等待条件
          使用非阻塞锁,一旦线程发现请求的锁被使用,就去释放自己拥有的锁
              pthread_mutex_trylock();
              int sem_trywait(sem_t *sem);

原因:进程间空间独立,无法直接通信,需要IPC机制实现通信。

同一主机进程间通信
1、古老的通信方式
        无名管道  
        有名管道  
        信号:进程间通知机制

2、IPC对象通信 system v    
        共享内存*:效率最高
        消息队列        
        信号量集 (信号灯)

主要用在不同主机进程间通信    
3、socket通信
        网络通信


IPC机制:
1. 管道
     有名管道:可以用于同一主机,任意进程间通信
     无名管道:只能用于同一主机,具有亲缘关系的进程间通信(父子进程间)

2. 无名管道

1)无名管道操作流程:
       1. 创建无名管道:pipe();
       2. 写管道--》write();
       3. 读管道--》read();
       4. 关闭管道--》close();

#include <stdio.h>
#include <unistd.h>


int main(int argc, const char *argv[])
{
	int pipefd[2];
	int ret = pipe(pipefd);
	if (ret < 0)
	{
		perror("pipe error");
		return -1;
	}
	pid_t pid = fork();
	if (pid > 0)
	{
		//pipefd[0]  --->read	
		//pipefd[1]  --->write
		close(pipefd[0]);
		write(pipefd[1], "hello world", 11);
		close(pipefd[1]);
		wait(NULL);
	}
	else if (0 == pid)
	{
		//pipefd[0] --->read
		//pipefd[1] --->write
		close(pipefd[1]);
		char buff[1024] = {0};
		read(pipefd[0], buff, sizeof(buff));
		printf("buff = %s\n", buff);
		close(pipefd[0]);
	}
	else
	{
		perror("fork error");
	}

	return 0;
}

2)管道本质:
      内核空间中的一段缓冲区,遵循先进先出特点。
      无名管道的:读端:pipefd[0]
                             写端:pipefd[1]
                             读写端不能交换。

      无名管道默认大小:65536bytes = 64K

3)管道的特性:

      1. 写阻塞:读端和写端都存在,向管道中写数据,当管道满时,发生写阻塞。
      2. 读阻塞:读端和写端都存在,从管道中读数据,若管道为空,则发生读阻塞。
      3. 读返回0:当写端关闭,从管道中读数据,若管道中有数据,则读到数据;
                            若管道中没有数据,read则返回0,不再阻塞。
      4. 管道破裂:读端关闭,向管道中写入数据,发生管道破裂(异常)

3. 有名管道

可以是任意进程间通信。

1)有名管道本质:
       内核空间的一段缓冲区,但这块缓冲区和一个管道文件相关联。

2)有名管道的操作流程:
      
       1. 创建管道文件 mkfifo、mkfifo();
       2. 打开管道文件 open();
       3. 写管道文件 write();
       4. 读管道文件 read();
       5. 关闭管道文件 close();
       6. 删除管道文件 int remove(const char *pathname);

        int mkfifo(const char *pathname, mode_t mode);
       功能:创建一个管道文件
       参数:
              pathname:管道文件的名称
              mode:管道文件的读写执行权限
       返回值:
            成功:0;
            失败:-1
 

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>

int main(int argc, const char *argv[])
{
	int ret = mkfifo("./myfifo", 0664);
	if (ret != 0 && errno != EEXIST)
	{
		perror("mkfifo error");
		return -1;
	}

	int fd = open("./myfifo", O_RDONLY);
	if (fd < 0)
	{
		perror("open error");
		return -1;
	}
	char buff[1024] = {0};

	ssize_t cnt = read(fd, buff, sizeof(buff));
	printf("cnt = %ld, buff = %s\n", cnt, buff);
	
	close(fd);

	remove("./myfifo");
	
	return 0;
}
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>


int main(int argc, const char *argv[])
{
	int ret = mkfifo("./myfifo", 0664);	
	if (ret != 0 && errno != EEXIST)
	{
		perror("mkfifo error");
		return -1;
	}
	int fd =  open("./myfifo", O_WRONLY);
	if (fd < 0)
	{
		perror("open error");
		return -1;
	}

	write(fd, "hello world", 11);
	close(fd);
	
	//remove("./myfifo");

	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值