1.用父子进程来同时读取键盘和鼠标
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(void)
{
int fd = -1;
int pid = -1;
char buf[200];
pid = fork();
if(pid == 0)
{
fd = open("/dev/input/mouse0",O_RDONLY);//打开鼠标
if(fd < 0)
{
perror("open");
return -1;
}
while(1)
{
memset(buf,0,sizeof(buf));
printf("before 鼠标 read\n");
//读取鼠标
read(fd,buf,5);//read默认是阻塞的
printf("鼠标读出的内容是:[%s]\n",buf);
}
}
else if(pid > 0)
{
while(1)
{
memset(buf,0,sizeof(buf));
printf("before 键盘 read\n");
//读取键盘键盘就是标准输入,stdin
read(0,buf,2);//read默认是阻塞的
printf("键盘读出的内容是:[%s]\n",buf);
}
}
else
{
perror("fork");
return -1;
}
return 0;
}
2.多进程的优缺点
(1)优点:CPU时分复用,单核心CPU可以实现宏观上的并行,实现多任务系统需求(多任务的系统需求是客观的)
(2)缺点:进程间切换开销大,进程间通信麻烦而且效率低,而线程就解决了这些麻烦。线程技术保留了进程技术实现多任务的他特性。线程的改进就是在线程间通信和切换上提升了效率。多线程在多核CPU上更有优势。
(3)用线程同时读取键盘和鼠标
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
char buf[200];
void *func(void *arg)
{
while(1)
{
memset(buf,0,sizeof(buf));
printf("before 键盘 read\n");
//读取键盘键盘就是标准输入,stdin
read(0,buf,2);//read默认是阻塞的
printf("键盘读出的内容是:[%s]\n",buf);
}
}
int main(void)
{
int fd = -1;
int ret = -1;
pthread_t th = -1;
//int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
// void *(*start_routine) (void *), void *arg);
ret = pthread_create(&th,NULL,func,NULL); //创建一个线程
if(ret != 0)
{
perror("pthread_create");
return -1;
}
//主任务
fd = open("/dev/input/mouse0",O_RDONLY);//打开鼠标
if(fd < 0)
{
perror("open");
return -1;
}
while(1)
{
memset(buf,0,sizeof(buf));
printf("before 鼠标 read\n");
//读取鼠标
read(fd,buf,5);//read默认是阻塞的
printf("鼠标读出的内容是:[%s]\n",buf);
}
return 0;
}
3.线程简介
(1)一种轻量级进程
(2)线程是参与内核调度的最小单元
(3)一个进程中可以有多个线程
4.线程技术的优势
(1)向进程一样可以被OS调度
(2)同一进程的多个线程之间很容易高效率通信
(3)在多核CPU架构下效率最大化
5.线程相关的函数
(1)pthread_create:主线程用来创建子线程
(2)pthread_join:主线程用来等待回收子线程
(3)pthread_detach:主线程用来分离子线程,分离后主线程不必再去回收子线程
6.线程取消
(1)pthread_cancel:一般是主线程调用该函数去取消(杀死)子进程。
(2)pthread_setcancelstate:子线程设置自己是否允许被取消
(3)pthread_setcanceltype:设置子线程取消模式
7.线程函数退出相关(线程自动退出)
(1)pthread_exit与return退出
(2)pthread_cleanup_push:给线程上锁
(3)pthread_cleanup_pop:给线程去锁
8.获取线程id
pthread_self
9.线程同步之信号量(实现计算一个字符串输入长度)
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <stdlib.h>
#include <semaphore.h>
char buf[500] = {0};
sem_t sem;
unsigned int flag = 0;
//子线程的作用是统计buf中的字符个数并打印
//子线程应该有个循环,循环中阻塞在等待主线程激活的时候,
//子线程被激活后就去获取buf中的字符长度,然后打印,完成后又被阻塞
void *func(void *arg)
{
//int sem_wait(sem_t *sem);等待信号量被激活函数
sem_wait(&sem);
while(strncmp(buf,"end",3))
{
printf("本次输入了%ld个字符\n",strlen(buf));
memset(buf,0,sizeof(buf));
sem_wait(&sem);
}
pthread_exit(NULL);
}
int main()
{
int ret = -1;
pthread_t th = -1;
//int sem_init(sem_t *sem, int pshared, unsigned int value);定义或初始化一个信号量
sem_init(&sem,0,0);
ret = pthread_create(&th,NULL,func,NULL);
if(ret != 0)
{
printf("pthread_creat error");
return -1;
}
printf("请输入一个字符串,以回车结束\n");
while(scanf("%s",buf))
{
if(!strncmp(buf,"end",3))
{
printf("程序结束\n");
flag = 1;
//int sem_post(sem_t *sem);激活信号量函数
sem_post(&sem);
break;
}
//主线程在收到用户输入的字符串并确认不是end后就去发信号量激活子线程来计数
//子线程被阻塞,主线程可以激活,这就是线程同步问题,用信号量来实现
sem_post(&sem);
}
//回收子线程
printf("等待回收子线程\n");
ret = pthread_join(th,NULL);
if(ret != 0)
{
printf("回收失败\n");
exit(-1);
}
printf("子线程回收成功\n");
//int sem_destroy(sem_t *sem);信号量摧毁函数
sem_destroy(&sem);
return 0;
}
9.线程同步之互斥所
(1)什么是互斥锁:互斥锁有叫互斥量
(2)相关函数:pthread_mutex_init、pthread_mutex_destroy、pthread_mutex_lock、pthread_mutex_unlock
(3)互斥锁和信号量的关系:可以认为互斥锁是一种特殊的信号量
(4)互斥锁主要用来实现关键段保护
注意:当使用上面几个库函数查看man手册时,找不到这个手册项目是需要按照man手册:sudo apt install manpages-posix-dev
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <semaphore.h>
#include <stdlib.h>
char buf[500] = {0};
pthread_mutex_t mutex;
unsigned int flag = 0;
//子线程的作用是统计buf中的字符个数并打印
//子线程应该有个循环,循环中阻塞在等待主线程激活的时候,
//子线程被激活后就去获取buf中的字符长度,然后打印,完成后又被阻塞
void *func(void *arg)
{
sleep(1);
while(flag != 1)
{
pthread_mutex_lock(&mutex);
printf("本次输入了%ld个字符\n",strlen(buf));
memset(buf,0,sizeof(buf));
pthread_mutex_unlock(&mutex);
sleep(1);
}
pthread_exit(NULL);
}
int main()
{
int ret = -1;
pthread_t th = -1;
//int pthread_mutex_init(pthread_mutex_t *restrict mutex,
// const pthread_mutexattr_t *restrict attr);
pthread_mutex_init(&mutex,NULL);
ret = pthread_create(&th,NULL,func,NULL);
if(ret != 0)
{
printf("pthread_creat error");
return -1;
}
printf("请输入一个字符串,以回车结束\n");
while(1)
{
//int pthread_mutex_lock(pthread_mutex_t *mutex);
pthread_mutex_lock(&mutex);//上锁
scanf("%s",buf);
pthread_mutex_unlock(&mutex);//解锁
if(!strncmp(buf,"end",3))
{
printf("程序结束\n");
flag = 1;
break;
}
sleep(1);
}
//回收子线程
printf("等待回收子线程\n");
ret = pthread_join(th,NULL);
if(ret != 0)
{
printf("回收失败\n");
exit(-1);
}
printf("子线程回收成功\n");
pthread_mutex_destroy(&mutex);
return 0;
}
10.线程同步之条件变量
(1)相关函数pthread_cond_init、pthread_cond_destroy、pthread_cond_wait、pthread_cond_signal(只能唤醒一个)、pthread_cond_broadcast(可以唤醒多个)
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <semaphore.h>
#include <stdlib.h>
char buf[500] = {0};
pthread_mutex_t mutex;
unsigned int flag = 0;
pthread_cond_t cond;
//子线程的作用是统计buf中的字符个数并打印
//子线程应该有个循环,循环中阻塞在等待主线程激活的时候,
//子线程被激活后就去获取buf中的字符长度,然后打印,完成后又被阻塞
void *func(void *arg)
{
while(flag != 1)
{
pthread_mutex_lock(&mutex);
//int pthread_cond_wait(pthread_cond_t *restrict cond,
// pthread_mutex_t *restrict mutex);
pthread_cond_wait(&cond,&mutex);//条件成立才往下执行
printf("本次输入了%ld个字符\n",strlen(buf));
memset(buf,0,sizeof(buf));
pthread_mutex_unlock(&mutex);
}
pthread_exit(NULL);
}
int main()
{
int ret = -1;
pthread_t th = -1;
//int pthread_mutex_init(pthread_mutex_t *restrict mutex,
// const pthread_mutexattr_t *restrict attr);
pthread_mutex_init(&mutex,NULL);
//int pthread_cond_init(pthread_cond_t *restrict cond,
// const pthread_condattr_t *restrict attr);
pthread_cond_init(&cond,NULL);
ret = pthread_create(&th,NULL,func,NULL);
if(ret != 0)
{
printf("pthread_creat error");
return -1;
}
printf("请输入一个字符串,以回车结束\n");
while(1)
{
//int pthread_mutex_lock(pthread_mutex_t *mutex);
//pthread_mutex_lock(&mutex);//上锁
scanf("%s",buf);
//int pthread_cond_signal(pthread_cond_t *cond);
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);//解锁
if(!strncmp(buf,"end",3))
{
printf("程序结束\n");
flag = 1;
break;
}
sleep(1);
}
//回收子线程
printf("等待回收子线程\n");
//int pthread_join(pthread_t thread, void **retval);
ret = pthread_join(th,NULL);
if(ret != 0)
{
printf("回收失败\n");
exit(-1);
}
printf("子线程回收成功\n");
//int pthread_mutex_destroy(pthread_mutex_t *mutex);
pthread_mutex_destroy(&mutex);
//int pthread_cond_destroy(pthread_cond_t *cond);
pthread_cond_destroy(&cond);
return 0;
}