【Linux】如何在进程间加锁(实现互斥)

文章目录

  • 前言
  • mmap 配合 pthread_mutex_t
    • 先让多个进程能够看到一个num
    • 多个进程互斥访问
    • 具体代码
  • 采用共享内存配合信号量
    • semget
    • semctl
    • semop
    • 核心逻辑
  • 管道
  • 总结


前言

【Linux】初识进程间通信:建议先读完这篇。

进程之间如何加锁,今天我们需要实现一个售票系统,我们需要对同一个num变量++。
以往我们写过类似的代码,只需要用pthread_mutex_t 这把锁就可以实现一个进程内多个线程互斥。但是我们这里改变需求,假设是你和你的同学需要抢一张票,你们在不同的主机的相同进程抢票,那么要怎么做呢?

mmap 配合 pthread_mutex_t


pthread_mutex_t要使用,需要pthread_mutexattr_t的帮助,将原先的线程锁换为进程锁。
mmap 这个函数功能是在共享区当中申请一块内存空间。
是将用户空间的一段内存区域映射到内核空间,映射成功之后,用户对这段内存区域的修改可以直接反映到内核空间。

先让多个进程能够看到一个num


那么我们可以定义一个结构体,mt结构体,其中num标识总票数,mutex是互斥锁,mutexattr是锁的属性。

void *mmap(void *addr, size_t length, int prot, int flags,
int fd, off_t offset);

struct mt
{int num; //多个进程的票数pthread_mutex_t mutex;pthread_mutexattr_t mutexattr;
};

mt 对齐,结构体对象对齐时按照其最大的对齐数进行对齐。 这里推荐把mutexattr写到mutex前面,因为这样总体消耗的内存最小。(56 -》 48)
在共享内存开辟mt空间大小,返回指针给两个进程。两个进程得到的指针值相同。

由于此处是父子进程,不需要依赖文件描述符,fd填写为-1,MAP_SHARED|MAP_ANON的组合标识需要保存的文件并且是匿名的mmap,仅在进程间使用。PROT_READ|PROT_WRITE标识这块共享区的读写权限。

匿名的mmap:

  • 适合父子进程使用
mm = (mt*)mmap(NULL,sizeof(*mm),PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANON,-1,0);

有名的mmap:

  • 打开一个文件,获取文件描述符
  • ftruncate进行设置文件大小,将文件大小设置成struct mt的大小,若原先文件大小超过sizeof(*mm),则会被截断为sizeof(*mm),若文件大小小于,则会扩到sizeof(*mm)
  • mmap进行设置,将共享内存当中开辟一块内存空间。
  • 关闭打开的文件描述符
  • 删除文件

注意 :MAP_SHARED不进行设置的话后续会报段错误。
这引入我们对flags变量的思考:

  • 若是设置成0,那么由于内核暂不支持,所以返回值会是MAP_FAILED,(void*)-1,也就是0xffffffffffffffff,那么后续对返回值做操作,都会出现段错误。
    在这里插入图片描述在这里插入图片描述
  • 若是设置为MAP_SHARED,两个进程是能够互斥访问的。在这里插入图片描述
  • 若是设置成MAP_PRIVATE,明显加的不是一个变量,说明父子发生写时拷贝,操作系统会在共享区开辟一块同属性的内存,让父进程或者子进程去读写。达不到进程同步。
    在这里插入图片描述
 int fd = open("mt_test",O_CREAT|O_RDWR,0777);// 打开文件,获得一个fdif( fd == -1 ) {perror("open file:"); exit(1); }
int n = ftruncate(fd,sizeof(*mm)); // 截取fd的部分mm = (mt*)mmap(NULL,sizeof(*mm),PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);close(fd);unlink("mt_test"); // 删除文件

两种创建mmap的方式是一种万金油,任意进程都可以使用,另一种适合父子通信。

多个进程互斥访问


pthread_mutex默认是线程间通信加的锁,要是想用在进程之间,需要pthread_mutexattr_t *restrict attr 填充这个字段,在属性字段当中修改为PTHREAD_PROCESS_SHARED标识进程间共享。

 pthread_mutexattr_init(&mm->mutexattr);        // 初始化 mutex 属性pthread_mutexattr_setpshared(&mm->mutexattr, PTHREAD_PROCESS_SHARED);               // 修改属性为进程间共享pthread_mutex_init(&mm->mutex,&mm->mutexattr);      
// 初始化一把 mutex 锁

上述工作过后,已经在共享区创建了一个结构体,并且父进程已经接受了指向共享区的指针,fork创建子进程之后父子进程都可以挂接在共享区上面。

在这里插入图片描述

接下来,父子实现互斥访问就简单了。使用之前只需要先用mm->mutex进行加锁即可。同理,若是放着的是原子变量,自旋锁,读写锁,也都是可以使用的。

pid = fork();if( pid == 0 )          // 子进程{for( i=0; i<10;i++ ){pthread_mutex_lock(&mm->mutex);(mm->num)++;printf("-child--------------num++    %d\n",mm->num);pthread_mutex_unlock(&mm->mutex);sleep(1);}}else {for( i=0;i<10;i++){sleep(1); pthread_mutex_lock(&mm->mutex);mm->num += 2;printf("--------parent------num+=2   %d\n",mm->num);pthread_mutex_unlock(&mm->mutex);}wait(NULL);}pthread_mutexattr_destroy(&mm->mutexattr);  // 销毁 mutex 属性对象pthread_mutex_destroy(&mm->mutex);          // 销毁 mutex 锁

具体代码

/*互斥量 实现 多进程 之间的同步 
*/#include<unistd.h>
#include<sys/mman.h>
#include<pthread.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<fcntl.h>
#include<string.h>
#include<stdlib.h>
#include<stdio.h>struct mt
{int num;pthread_mutex_t mutex;pthread_mutexattr_t mutexattr;
};// 通过父子进程对同一个变量 mm->num 进行++ ,父进程一次+2 ,子进程一次 +1
int main(void)
{int i;struct mt* mm;pid_t pid;// 创建映射区文件int fd = open("mt_test",O_CREAT|O_RDWR,0777);if( fd == -1 ) {perror("open file:"); exit(1); }ftruncate(fd,sizeof(*mm));mm = (mt*)mmap(NULL,sizeof(*mm),PROT_READ|PROT_WRITE,MAP_SHARED ,fd,0);close(fd);unlink("mt_test");//就是这个mt结构体,当我们创建mt// 建立映射区 MAP_ANON匿名映射//mm = (mt*)mmap(NULL,sizeof(*mm),PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANON,-1,0);//    printf("-------before memset------\n");//memset(mm,0x00,sizeof(*mm));//   printf("-------after memset------\n");pthread_mutexattr_init(&mm->mutexattr);         // 初始化 mutex 属性pthread_mutexattr_setpshared(&mm->mutexattr, PTHREAD_PROCESS_SHARED);               // 修改属性为进程间共享pthread_mutex_init(&mm->mutex,&mm->mutexattr);      // 初始化一把 mutex 锁pid = fork();if( pid == 0 )          // 子进程{for( i=0; i<10;i++ ){pthread_mutex_lock(&mm->mutex);(mm->num)++;printf("-child--------------num++    %d\n",mm->num);pthread_mutex_unlock(&mm->mutex);sleep(1);}}else {for( i=0;i<10;i++){sleep(1); pthread_mutex_lock(&mm->mutex);mm->num += 2;printf("--------parent------num+=2   %d\n",mm->num);pthread_mutex_unlock(&mm->mutex);}wait(NULL);}pthread_mutexattr_destroy(&mm->mutexattr);  // 销毁 mutex 属性对象pthread_mutex_destroy(&mm->mutex);          // 销毁 mutex 锁return 0;
}

采用共享内存配合信号量


信号量我们使用System V的这套接口。在说到具体的实现方案,不得不说分辨一下System V的信号量,Posix V的信号量,Posix还分为有名和无名的信号量。

System V的特点是同时能操作多个信号量,接口使用难度比Posix要复杂,移植性不太好。
Posix 是
解释一下为什么Posix 无名信号量适合线程同步,因为sem_init是将信号集sem_t进行初始化,而若要实现进程间的互斥,需要多个进程看到sem_t,就需要借助其他手段让其他进程看到sem_t。

System V的信号量是随内核的。
Posix有名信号灯的值是随内核持续的。
Posix无名信号灯的持续性却是不定的,因为他是基于内存的,如果基于内存的信号灯是由单个进程内的各个线程共享的,那么该信号灯就是随进程持续的,当该进程终止时它也会消失。
总结:

  • 1、System V的信号量一般用于进程同步, 且是内核持续的, api为:semget、semctl、semop
  • 2、Posix的有名信号量一般用于进程同步, 有名信号量是内核持续的. 有名信号量的api为:sem_open、sem_close、sem_unlink
  • 3、Posix的无名信号量一般用于线程同步, 无名信号量是进程持续的, 无名信号量的api为:sem_init、sem_destroy

先介绍一下接口:

semget

int semget(key_t key, int nsems, int semflg);

  • key通常可以由ftok创建
  • nsems标识需要创建多少个信号量,我通常只需要操纵一个,所以这里填写1
  • semflg标识信号量的权限,服务端通常IPC_CREAT | IPC_EXCL都带上,标识创建一个新的IPC资源,客户端可以填0。
  • 返回值就是semid,标识内核维护的IPC资源的下标(操作系统是用数组维护IPC资源的ipc_perm),出错返回-1.
    在这里插入图片描述

在这里插入图片描述

semctl

int semctl(int semid, int semnum, int cmd, …);

  • semid:就是semget获得的返回值
  • semnum:semget传参的时候nsems,这里要操作的就是0~nsems-1的信号集
  • cmd:标识对内核维护的信号量做什么操作,如:SETVAL,IPC_RMID,注意初始化值的时候应用SETVAL并非IPC_SET,IPC_SET是指用户层创建了一个结构体,用这个结构体的字段重新多创建一个IPC资源(我的理解,仅供参考)
  • …:这里的可变参数需要我们传多一个用户层自定义的结构体,这里参考内核的union semun,我们定义了semun后,设置val等同于设置该信号量为几元信号量,犹如设置1,那么他就可以为0或者1,也称之为二元信号量搭配SETVAL使用。这里我们只是实现互斥,所以此处填写1。
  • 返回值:失败返回-1

下方为内核,实际我们编写的时候可以只有int val这个字段。

union semun {int     val;   /* Value for SETVAL */
struct semid_ds *buf;    
/* Buffer for IPC_STAT, IPC_SET */
unsigned short  *array;  
/* Array for GETALL, SETALL */struct seminfo  *__buf;  /* Buffer for IPC_INFO(Linux-specific) */};

semop

int semop(int semid, struct sembuf *sops, unsigned nsops);

  • semid:semget返回值
  • sops:sem_num 标识需要操作的信号集具体是哪个,如果只创建了一个,那么这里是0;sem_op标识进行何种操作,此处填写-1标识获取当前信号量,填写1标识归还信号量;sem_flg表示以何种方式进行semop操作,若是阻塞,则填0,还有类似IPC_NOWAIT,SEM_UNDO(通常为SEM_UNDO,使操作系统跟踪信号,并在进程没有释放该信号量而终止时)等字段
  • nsops标识操作第几块IPC资源:这里若semget填写的是1,这里也填写1,标识操作第一块信号量,这里就不是从0开始了。
  • 返回值:-1标识错误
struct sembuf{
unsigned short sem_num;  /* semaphore number */
short          sem_op;   /* semaphore operation */
short          sem_flg;  /* operation flags */
}

核心逻辑


父进程创建共享内存,创建信号量,由信号量标识当前资源是否被使用,由共享内存将真正的数据(ticket)放到共享区当中。当父子任意进程访问ticket,都需要semop获得信号量,这样就能保证临界资源受到保护了。

需要注意的是,可以将信号量,共享内存在fork之前创建,之后调用接口不会引起写时拷贝。

--*pticket;不要写成 *pticket --; Linux下会出现问题!!!!

  • semop(semid, &sb, 1) == -1 && EAGAIN == errno可以用来标识semctl删除信号量,op操作自然会失败,errno为EAGAIN。semop(semid, &sb, 1) == -1 也可以作为判断。
  • 最终票数为0,父子进程都调用semctl删除共享资源,只有一方会调用成功,当父子进程都semdt取消挂接后该资源便会释放。共享内存和信号量都需要调用对应接口,否则会造成资源泄露,都是随内核的。
#include <iostream>
using namespace std;
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/shm.h>union semun
{int val;               /* value for SETVAL */struct semid_ds *buf;  /* buffer for IPC_STAT, IPC_SET */unsigned short *array; /* array for GETALL, SETALL */struct seminfo *__buf; /* buffer for IPC_INFO */
};
int main()
{int key = ftok("sem_sys.cc", 9000);int shm_key = ftok(".", 8080);int shmid = shmget(shm_key, 4096, IPC_CREAT | IPC_EXCL | 0644);if (shmid < 0){perror("shmget");return 1;}int *pticket = (int *)shmat(shmid, nullptr, 0);*pticket = 1000; // 1000张票int semid = semget(key, 1, IPC_CREAT | IPC_EXCL | 0644);if (semid < 0){perror("semget");return 2;}semun se;se.val = 1;//标识单个信号量的资源大小,互斥填1,这里就会两态。// SETVAL   IPC_SETint res = semctl(semid, 0, SETVAL, se);if (res == -1){perror("semctl");return 4;}pid_t id = fork();if (id == 0){while (1){// childstruct sembuf sb; // Psb.sem_flg = 0;   //阻塞拿sb.sem_num = 0;   //拿第一个sb.sem_op = -1;   //获取信号量if (semop(semid, &sb, 1) == -1 && EAGAIN == errno)break;// cout << "child " << *pticket_child << endl;//获得了这个信号量if (*pticket <= 0){semctl(semid, 0, IPC_RMID);break;}--*pticket;cout << "child get ticket: " << *pticket << endl;usleep(1);// Vstruct sembuf sb2;sb2.sem_flg = 0;sb2.sem_num = 0;sb2.sem_op = 1;//释放信号量semop(semid, &sb2, 1);}shmdt(pticket);}else{while (1){// fatherstruct sembuf sb; // Psb.sem_flg = 0;sb.sem_num = 0;sb.sem_op = -1;if (semop(semid, &sb, 1) == -1 && EAGAIN == errno)break;//获得了这个信号量// cout << "father " << *pticket_father << " :" << &pticket_father << endl;if (*pticket <= 0){semctl(semid, 0, IPC_RMID);break;}--*pticket;cout << "father get ticket: " << *pticket << " :" << &pticket << endl;usleep(1);// Vstruct sembuf sb2;sb2.sem_flg = 0;sb2.sem_num = 0;sb2.sem_op = 1;semop(semid, &sb2, 1);}shmdt(pticket);shmctl(shmid, IPC_RMID, nullptr);}return 0;
}

一开始担心会发生写时拷贝写的版本,让子进程让出时间片给父进程创建信号量和共享内存,子进程后进行挂接。

#include <iostream>
using namespace std;
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/shm.h>union semun
{int val;               /* value for SETVAL */struct semid_ds *buf;  /* buffer for IPC_STAT, IPC_SET */unsigned short *array; /* array for GETALL, SETALL */struct seminfo *__buf; /* buffer for IPC_INFO */
};
int main()
{pid_t id = fork();if (id == 0){usleep(100); //让父进程先启动int key = ftok("sem_sys.cc", 9000);int shm_key = ftok(".", 8080);//child 负责连接int shmid = shmget(shm_key, 0, 0);//获取共享内存if(shmid < 0){perror("shmget");return 1;}int *pticket_child = (int *)shmat(shmid, nullptr, 0);//获取ticketint semid = semget(key, 1, 0);//获取信号量//cout << "child semid " << semid <<endl;if(semid < 0){perror("semget");return 2;}while (1){// childstruct sembuf sb; // Psb.sem_flg = 0;   //阻塞拿sb.sem_num = 0;   //拿第一个sb.sem_op = -1;   //拿一个if (semop(semid, &sb, 1) == -1 && EAGAIN == errno)break;//cout << "child " << *pticket_child << endl;//获得了这个信号量if (*pticket_child <= 0){semctl(semid, 0, IPC_RMID);break;}--*pticket_child;cout << "child get ticket: " << *pticket_child << endl;usleep(1);// Vstruct sembuf sb2;sb2.sem_flg = 0;sb2.sem_num = 0;sb2.sem_op = 1;semop(semid, &sb2, 1);}shmdt(pticket_child);}else{int key = ftok("sem_sys.cc", 9000);int shm_key = ftok(".", 8080);int shmid = shmget(shm_key, 4096, IPC_CREAT | IPC_EXCL | 0644);if(shmid < 0){perror("shmget");return 1;}int *pticket = (int *)shmat(shmid, nullptr, 0);*pticket = 1000; // 1000张票int semid = semget(key, 1, IPC_CREAT | IPC_EXCL | 0644);//cout << "father semid " << semid <<endl;if(semid < 0){perror("semget");return 2;}semun se;se.val = 1;// SETVAL   IPC_SETint res = semctl(semid, 0, SETVAL, se);if(res == -1){perror("semctl");return 4;}int *pticket_father = pticket;while (1){// fatherstruct sembuf sb; // Psb.sem_flg = 0;sb.sem_num = 0;sb.sem_op = -1;if (semop(semid, &sb, 1) == -1  && EAGAIN == errno)break;//获得了这个信号量//cout << "father " << *pticket_father << " :" << &pticket_father << endl;if (*pticket_father <=   0){semctl(semid, 0, IPC_RMID);break;}--*pticket_father;cout << "father get ticket: " << *pticket_father << " :" << &pticket_father << endl;usleep(1);// Vstruct sembuf sb2;sb2.sem_flg = 0;sb2.sem_num = 0;sb2.sem_op = 1;semop(semid, &sb2, 1);}shmdt(pticket_father);shmctl(shmid,IPC_RMID,nullptr);}return 0;
}

管道

【Linux】初识进程间通信
之前写的这篇文章由叙述,管道在65536内是支持原子性的,小于PIPE_BUF都能保证原子性,读写只能一端运行,内部就实现了互斥同步,要双向通信就开两个即可。

参考:
被遗忘的桃源——flock 文件锁
进程间锁:进程间pthread_mutex,文件锁

总结


  • 实际上我个人偏向于mmap的这种方式,因为当进程crash的时候,mmap可以保存到文件,但他和shm面临着共享内存被锁上无法使用的问题。
  • mmap和共享内存二者本质上是类似的,mmap可以看到文件的实体,而 shmget 对应的文件在交换分区上的 shm 文件系统内,无法直接cat 查看。
  • 因为文件锁flock在进程crash时,操作系统会清理掉,所以比较推荐使用flock作为进程的锁资源。(可以参考当中读读那个文章。)
  • 而信号量本身不能传递复杂消息,只能用来同步互斥。

进程间加锁目前我所知道的以上三种方式已经成列,由于能力有限,若有错误,欢迎评论区指出。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/41555.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

windows邮箱无法登录腾讯企业邮箱

问题如图&#xff1a; “更改设置”&#xff1a;添加exmail. “修复账户”&#xff0c;重新输入密码

在自己电脑上无法用Foxmail客户端登录126邮箱的解决办法

在公司的电脑上使用了Foxmail邮箱&#xff0c;并且把126帐号也关联在那了。但是发现回到家之后&#xff0c;在自己电脑上用Foxmail登录自己的126邮箱帐号老是报一个登录帐号或密码错误&#xff0c;弄了几天&#xff0c;今天终于搞定了。 解决办法&#xff1a;1.在网页上登录12…

微软账号更改登录首邮箱后原邮箱还会收到信息解决(更改不彻底)

问题 微软账号可以在个人资料页面更改首邮箱&#xff0c;有时候我们需要更改或者添加其他邮箱以保证更加安全&#xff1a; 但是有时候即使更改了&#xff0c;原来的邮箱还会收到相关邮件是怎么回事呢&#xff1f; 解决 问题在于安全邮箱没有更改。注册的时候已经默认将你填…

解决outlook不能访问hotmail邮箱的问题

outlook设置188邮箱&#xff0c;很简单&#xff0c;直接输入用户名和密码就行。 但是设置hotmail时却遇到问题&#xff0c;如果还是自动设置&#xff0c;会提示让下载outlook hotmail connector&#xff0c;但是下载安装好&#xff0c;也没啥用&#xff1b; 还有说去下载两个…

Gmail、Yahoo 和 Microsoft Outlook高危

By Jeffrey - 资深IT经理人和IT顾问&#xff0c;历任多家知名跨国企业包括麦肯锡、通用电气公司、壳牌石油、英美烟草等公司IT总经理 根据Neowin的报道&#xff0c;黑客使用工具可以下载 Gmail、Yahoo 和 Microsoft Outlook 收件箱&#xff0c; 谷歌的威胁分析小组 (Threat An…

手贱装了win10之后用hotmail的邮箱登录了小娜

http://zhidao.baidu.com/link?urlbEZCiyWGvRWWjB9l72bLxTzarGeINpiyT8Ud3OmrdrSe3VoPNKrkFogt_DQnBliEEAPxXniQM1dn_PmGfPY1Gwe4QCcxmRR7EOoEtfRAKK7手贱装了win10之后用hotmail的邮箱登录了小娜&#xff0c;结果现在管理员账户就直接绑定了这个邮箱&#xff0c;现在每次开机…

性价比最高的网关?小米智能多模网关、绿米Aqara网关还是智汀多模智能网关?

如果你点进来只是想知道买哪款网关&#xff0c;那小编可直接说&#xff0c;如果你需要买蓝牙mesh子设备&#xff0c;又没有蓝牙Mesh网关/音箱&#xff0c;建议买小米智能多模网关&#xff1b;如果你不需要用蓝牙Mesh设备&#xff0c;需要用Aqara Home平台&#xff0c;那么就买绿…

小米智能家庭接入亚马逊Echo

效果&#xff1a;效果视频 本文讲述到的器材&#xff1a;Echo Dot&#xff08;当然也可以接入其他设备&#xff09;&#xff0c;极路由1S&#xff08;已经开启极客模式&#xff0c;理论上只要能进入ssh的路由器都可以&#xff09;&#xff0c;小米网关&#xff0c;温湿度传感器…

除了绿米它也能连接homekit,智汀到底有什么本领?

智能家居这个词近几年非常地火热&#xff0c;越来越多地智能家居出现在我们的视野当中。 当然我们可能还没有生活在“智能家居”的世界中&#xff0c;但是我们正在实现这一目标。 消费者开始为家中配备连接的灯&#xff0c;锁&#xff0c;警报器&#xff0c;摄像机&#xff0…

树莓派 + Home Assistant + HomeKit 从零开始打造个人智能家居系统 篇二:初步配置 Home Assistant 并连接小米设备与 HomeKit

树莓派 Home Assistant HomeKit 从零开始打造个人智能家居系统 篇二&#xff1a;初步配置 Home Assistant 并连接小米设备与 HomeKit 通过本篇教程&#xff0c;你将完成对 Home Assistant 的初步配置&#xff0c;接入小米智能家居设备&#xff0c;并在安装配置 Home Bridge …

智汀如何让绿米Aqara无线开关一键联动不同品牌的智能设备?以智汀窗帘电机、星辰智能台灯为例

上期跟大家说过智汀可以不通过Home Assistant系统就可以接入不同品牌的智能家居设备&#xff0c;那究竟 是如何接入的呢&#xff1f;今天小编就手把手教学&#xff1a; 要注意&#xff0c;一定要先在智汀家庭云APP里安装好智慧中心&#xff08;SA&#xff09;。 打开APP 场景…

一站式、整套智能家居解决方案——HomeKit?绿米?华为还是智汀?

越来越多的智能家居消费者希望能够获取一站式、一整套智能家居解决方案。有需求就有市场&#xff0c;现在一般的大厂大品牌都有全套的智能家居解决方案&#xff0c;比如HomeKit、绿米、华为和智汀等。 先给大家说一下如何基于苹果的HomeKit生态系统去搭建全屋智能——首先是Ye…

炎炎夏日教你利用小米智能家居配件+树莓派4接入Apple HomeKit

前言 Apple HomeKit智能家居方案&#xff0c;是苹果2016年在WWDC大会上提出来的&#xff0c;至今已经6个年头。在国内一直是不温不火的状态&#xff0c;除了有小米智能家居的米家方案等一大堆国内厂商跟进外&#xff0c;苹果特有的“贵”也是其阻碍因素之一&#xff0c;一个智…

绿米Aqara、智汀、Homekit等设备如何完成一键跨品牌联动

前言 一直以来只要提到智能家居&#xff0c;很多人的认知就是能使家中原有的家电变为智能化。本文将带大家来了解绿米Aqara、智汀、Homekit等设备如何完成一键跨品牌联动&#xff1f; 在操作之前&#xff0c;我们先来回顾下米家设备&#xff1a;Aqara作为唯一个能够连接HomeK…

如何将homekit接入安卓设备,homeassistant和智汀来帮忙

随着科技的发展&#xff0c;智能家居也开始慢慢火了起来&#xff0c;被越来越多的人所熟知。 在接触到智能家居的时候&#xff0c;大家或许都有一种我也弄来试试的冲动&#xff0c;所以会不会遇到以下的一些问题。 大家是不是常常有这些烦恼&#xff1a;家里装修买了智能设备…

绿米、易来和Yeelight设备之间的互相联动离不开智汀

不知道作为智能家居用户的你有没有这种经历&#xff1a;新买回来的智能设备&#xff0c;除了刚拿到它那天好奇耍了一会&#xff0c;后面再也没有用过&#xff0c;买的时候有多高兴&#xff0c;买回来就有多痛苦&#xff0c;特别是我们多少都有点消费冲动的hhh。 其实很多朋友不…

绿米Aqara智能设备还能这样玩?

大家好&#xff0c;今天给大家介绍的是绿米Aqara旗下的产品&#xff0c;我们都知道Aqara目前已经接入了小爱同学、天猫精灵、Apple Homekit等知名生态&#xff0c;因此可以实现多种生态的语音控制。但是通过我们后面测试发现目前只有小爱同学可以实现全局的控制&#xff0c;而天…

米家接入HomeKit系列一:接入基本原理与开篇

系列文章 米家接入HomeKit系列一&#xff1a;接入基本原理与开篇 米家接入HomeKit系列二&#xff1a;通过群辉NAS的Docker搭建HomeAssistant 米家接入HomeKit系列三&#xff1a;HomeAssistant接入米家网关 米家接入HomeKit系列四&#xff1a;HomeBridge搭建、配置与接入米家…

loT行业生死竞速:Aqara绿米得用户得天下

作者 | 曾响铃 文 | 响铃说 日前&#xff0c;社科院发布了一份“2022年秋季中国宏观经济形势分析”报告&#xff0c;报告中指出当前&#xff0c;世界经济增长预期下挫&#xff0c;全球通胀居高不下&#xff0c;而中国经济整体仍呈持续恢复状态&#xff0c;但经济内增长动能仍…

不用Home Assistant让小米智能家居接入HomeKit

这种方法不难&#xff0c;但支持的设备比较少&#xff0c;如果家里小米智能家居设备较多&#xff0c;又没有绿米网关的话&#xff0c;就还是算了吧。 方法是通过开源平台智汀的 Smart Assistant 装在 X86 主机或者群晖之类的设备上&#xff0c;然后加入 HomeKit 的插件包&#…