嵌入式Linux多任务:进程,线程
单任务:一个任务执行完毕之后,下个任务才能执行
多任务:任务的执行可以被中断,中断之后可以执行其他任务(并发,并行)
单核CPU:并发
多核CPU:并发,并行
进程实现多任务:特点:给每个进程分配独立的地址空间,4G大小(1G内核,3G用户空间)
进程创建方式:fork>exec函数族>system>vfork
进程的退出:exit()库函数/清理缓冲
-exit()系统调用/不清理缓冲
进程的等待:wait();解决僵尸进程
学习目标:学会创建多任务进程
进程间通信(IPC)方式
广义上进程间的通信
进程——文件——进程
进程——数据库——进程
例如下面代码所示(通过文件进行通信)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
pid_t pid;
`` pid = fork();
if (pid == -1)
{
perror("fork error!");
exit(1);
}
if (pid == 0)
{
//普通文件
int fd = open("b.txt", O_CREAT | O_WRONLY, 0655);
if (fd == -1)
{
perror("open file error!");
exit(1);
}
char buf[100] = "hello world";
write(fd, buf, strlen(buf));
close(fd);`
}
else if (pid > 0)
{
sleep(1);
int fd = open("b.txt", O_RDONLY);
if (fd == -1)
{
perror("open file error!");
exit(1);
}
char buf[100] = {0};
read(fd, buf, sizeof(buf));
printf("rec buf = %s\n",buf);
close(fd);
return 0;
}
狭义上进程间的通信
分为:管道,信号,消息队列,共享内存,信号量,套接字
管道
无名管道:只允许父子进程间通信
API: int pipe(int pipefd[2]);
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
pid_t pid;
int fd[2];
if (pipe(fd) < 0)
{
perror("pipe fork error!");
exit(1);
}
pid = fork();
if (pid == -1)
{
perror("fork error!");
exit(1);
}
if (pid == 0)
{
//无名管道
close(fd[0]);
char buf[100];
while (1)
{
scanf("%s", buf);
write(fd[1], buf, strlen(buf));
}
}
else if (pid > 0)
{
char buf[100] = {0};
while (1)
{
int len = read(fd[0], buf, sizeof(buf));
buf[len] = '\0';
printf("recv = %s\n", buf);
}
return 0;
}
有名管道**:任意两个进程间通信
API: int mkfifo(const char *pathname,mode_t mode)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
pid_t pid;
if (mkfifo("/tmp/p1", 0644) < 0)
{
perror("mkfifo error!");
exit(1);
}
pid = fork();
if (pid == -1)
{
perror("fork error!");
exit(1);
}
if (pid == 0)
{
int fd = open("/tmp/p1", O_WRONLY);
if (fd == -1)
{
perror("open file error!");
exit(1);
}
char buf[100] = {0};
while (1)
{
scanf("%s", buf);
write(fd, buf, strlen(buf));
}
}
else if (pid > 0)
{
int fd = open("/tmp/p1", O_RDONLY);
if (fd == -1)
{
perror("open file error!");
exit(1);
}
char buf[100] = {0};
while (1)
{
int len = read(fd, buf, sizeof(buf));
buf[len] = '\0';
printf("recv = %s\n", buf);
}
}
return 0;
}
下面是任意两个进程间通信的代码
write.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
int fd = open("/tmp/p1", O_WRONLY);
if (fd == -1)
{
perror("open file error!");
exit(1);
}
char buf[100] = {0};
while (1)
{
scanf("%s", buf);
write(fd, buf, strlen(buf));
}
return 0;
}
read.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
if (mkfifo("/tmp/p1", 0644) < 0)
{
perror("mkfifo error!");
exit(1);
}
int fd = open("/tmp/p1", O_RDONLY);
if (fd == -1)
{
perror("open file error!");
exit(1);
}
char buf[100] = {0};
while (1)
{
int len = read(fd, buf, sizeof(buf));
buf[len] = '\0';
printf("recv = %s\n", buf);
}
return 0;
}
消息队列
传送有格式的消息流
多进程网状交叉通信时,消息队列是上上之选
能实现大规模数据通信
API(4个)
int msgget (key_t key,int msgflag) (创建消息队列)
int msgsnd (int msqid,const voidmsgp,size_t msgsz,int msgflg) //将消息写入到消息队列
ssize_t msgrcv (int msqid,voidmsgp,size_t msgsz,long msgtyp,int msgflg)//从消息队列读取消息
int msgctl(int msqid,int cmd,struct msqid_ds*buf) //释放消息队列
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
struct msgbuf
{
/* data */
long id;
char buf[100];
};
int main()
{
pid_t pid;
key_t key;
key = ftok("/tmp/1", 'a');
//msgid消息队列描述符 == 文件描述符
int msgid = msgget(key, IPC_CREAT | 0644);
//int msgid = msgget(IPC_PRIVATE, IPC_CREAT | 0644);
if (msgid < 0)
{
perror("msg get error!");
exit(1);
}
pid = fork();
if (pid < 0)
{
perror("fork error!");
exit(1);
}
if (pid == 0)
{
//msgid
struct msgbuf msg;
msg.id = 1;
strcpy(msg.buf, "hello world");
msgsnd(msgid, &msg, sizeof(struct msgbuf), 0);
msg.id = 2;
strcpy(msg.buf, "hello world2");
msgsnd(msgid, &msg, sizeof(struct msgbuf), 0);
msg.id = 3;
strcpy(msg.buf, "hello world3");
msgsnd(msgid, &msg, sizeof(struct msgbuf), 0);
}
else if (pid > 0)
{
//msgid
struct msgbuf msg;
msgrcv(msgid, &msg, sizeof(struct msgbuf), 2, 0);
printf("recv:%s\n", msg.buf);
wait(NULL);
msgctl(msgid,IPC_RMID,NULL);
}
return 0;
}
共享内存
特点:减少了进入内核空间的次数,效率高
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int main()
{
pid_t pid;
key_t key;
key = ftok("/tmp/kk", 'k');
int shmid = shmget(key, 1024, IPC_CREAT | 0644);
if (shmid < 0)
{
perror("shm get error!");
exit(1);
}
pid = fork();
if (pid < 0)
{
perror("fork error!");
exit(1);
}
if (pid == 0)
{
//shmid
void *addr = shmat(shmid, NULL, 0);
char buf[100] = {0};
while (1)
{
scanf("%s", buf);
strcpy((char *)addr, buf);
sleep(1);
}
}
else if (pid > 0)
{
//shmid
sleep(1);
void *addr = shmat(shmid, NULL, 0);
while (1)
{
if (strlen((char *)addr) > 0)
{
printf("recv = %s\n", (char *)addr);
}
else
{
printf("no data!");
}
sleep(1);
}
}
return 0;
}
信号量
当多个进程/线程进行共享操作时,用于资源保护,以防止出现相互干扰的情况出现
互斥
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int main()
{
pid_t pid;
key_t key = ftok("/tmp/5", 'p');
int semid = semget(key, 1, IPC_CREAT | 0644);
if(semid < 0)
{
perror("sem get error!");
exit(1);
}
if(semctl(semid,0,SETVAL,1) < 0)
{
perror("semctl error!");
exit(1);
}
if ((pid = fork()) < 0)
{
perror("frok error!");
exit(1);
}
//b.txt
if (pid == 0)
{
//"hello world\n"
int fd = open("b.txt", O_WRONLY);
if (fd == -1)
{
perror("open file error!");
exit(1);
}
struct sembuf sem;
sem.sem_num = 0;
sem.sem_flg = SEM_UNDO;
while (1)
{
//-1 p
sem.sem_op = -1;
semop(semid,&sem,1);
write(fd, "hello", 5);
write(fd, "world", 5);
write(fd, "\n", 1);
sem.sem_op = +1;
semop(semid,&sem,1);
//v
//+1
//sleep(1);
}
}
else if (pid > 0)
{
//"hhhhh wwwww\n"
int fd = open("b.txt", O_WRONLY);
if (fd == -1)
{
perror("open file error!");
exit(1);
}
struct sembuf sem;
sem.sem_num = 0;
sem.sem_flg = SEM_UNDO;
while (1)
{
//-1
sem.sem_op = -1;
semop(semid,&sem,1);
write(fd, "hhhhh", 5);
write(fd, "wwwww", 5);
write(fd, "\n", 1);
sem.sem_op = +1;
semop(semid,&sem,1);
//+1
//sleep(1);
}
}
return 0;
}
未完待续