1、进程线程之间的区别:
进程和线程的根本区别是进程是操作系统(OS)资源分配的基本单位,而线程是处理器(CPU)任务调度和执行的基本单位
地址空间:线程共享本进程的地址空间,而进程之间是独立的地址空间。
资源:线程共享本进程的资源如内存、I/O、cpu等,不利于资源的管理和保护,而进程之间的资源是独立的,能很好的进行资源管理和保护。
健壮性:多进程要比多线程健壮,一个进程崩溃后,在保护模式下不会对其他进程产生影响,但是一个线程崩溃整个进程都死掉。
执行过程:每个独立的进程有一个程序运行的入口、顺序执行序列和程序入口,执行开销大。但是线程不能独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制,执行开销小。
可并发性:两者均可并发执行。
任务切换时:进程切换时,消耗的资源大,效率高。所以涉及到频繁的切换时,使用线程要好于进程。同样如果要求同时进行并且又要共享某些变量的并发操作,只能用线程不能用进程。
2、同步和异步通信
同步通信:面向比特流的通信发送方和接收方在同一时刻进行数据传输。为了实现这一点,通常需要一个时钟信号来协调数据的发送和接收。常见的同步通信协议包括I2C和SPI。时序一致性,响应确认,高传输速率。
异步通信:面向字节(8位)的通信,发送方和接收方之间没有严格的时序要求,它们可以独立进行操作,而无需等待对方的响应。数据一旦在发送方准备好,就可以立即发送,接收方在收到数据后进行处理。常见的异步通信协议包括UART。无时钟信号,适合长距离通信和不规则数据传输,潜在的延迟和速率。
3、阻塞IO和非阻塞IO
阻塞IO:内核IO操作彻底完成后,才返回到用户空间执行用户的操作。阻塞是指用户空间的执行状态。
非阻塞IO:用户空间的程序不需要等待内核IO操作彻底完成,可以立即返回用户空间执行用户操作,即处于非阻塞IO状态,内核空间会立即返回给用户一个状态值。
阻塞IO:调用线程一直在等待,不能干别的事情。
非阻塞IO:调用线程拿到内核返回的状态值后,IO操作能执行就执行,不能执行就执行别的线程。
4、并发和并行
并发:系统在同一时间段内处理多个任务的能力。并发关注的是任务之间的交替执行,任务之间可能并不真正同时运行,而是通过任务的分时调度机制,使得多个任务在时间上交错进行,从而给用户一种“同时”执行的感觉
并行:系统同时执行多个任务的能力。并行是指在多个处理器或者多核处理器上,真正同时地运行多个任务。并行化的目标是提高程序的执行效率,特别是在需要处理大量数据或计算密集型任务时,并行化可以显著减少任务的完成时间。
5、什么是死锁,如何避免死锁?
死锁是指在多线程多进程环境中,两个或多个进程(或线程)互相持有对方所需资源,导致它们都无法继续执行的一种状态。
避免嵌套锁:尽量避免在持有一个锁的时候去申请另一个锁,因为这样可能会导致死锁的发生。统一获取锁的顺序:如果多个线程需要获取多个锁,可以约定获取锁的顺序,这样可以避免出现死锁。设置超时时间:在获取锁的时候可以设置超时时间,如果超过一定时间还没有获取到锁,就放弃获取锁并释放已经获取的锁。死锁检测:通过检测程序的锁状态来判断是否存在死锁,并进行相应的处理。减少锁的持有时间:尽量减少持有锁的时间,使得锁的争用时间变短,从而减少死锁的发生概率。
6、进程间的通信方式有哪些
无名管道:亲缘进程通信
有名管道:任意进程通信
信号:用户可以给某个进程发送信号,一个进程也能给另一个进程发送信号,内核也可以给某个进程发送信号,信号三种默认操作:默认,捕获,忽略。
消息队列:多个进程可同时向一个消息队列发送消息,也可以同时从一个消息队列中接收消息。发送进程把消息发送到队列尾部,接受进程从消息队列头部读取消息,消息一旦被读出就从队列中删除
共享内存:共享内存是将物理空间的一片区域映射到内核空间,在将映射的内核空间与用户空间的区域进行连接。共享内存的操作不是一次性的,当共享内存段中的数据被读取后,依然存在。共享内存是所有进程间通信方式中效率最高的,原因是,操作共享内存段时,无需进行用户空间和内核空间的切换。
信号灯集:信号号灯集中的每一个灯,都控制一个进程信号灯集中的等的编号都是从0开始,信号灯集中的每个灯都维护了一个value值,当value为0时,处于阻塞状态,等待其他进程将该资源的值加到1。
套接字:内核提供的函数,用于创建一个套接字,并返回当前套接字的文件描述符,通过套接字文件描述符可以实现多个进程之间的通信,可以通过文件描述符进程进程之间的绑定。
线程间的同步互斥
1、线程可以通过全局变量和局部变量实现数据通信。
2、进程运行空间都是独立的,不能进行数据通信
3、多线程间数据共享有可能执行同一个动作,导致数据异常,所以要加上互斥锁。
4、多线程除了互斥之外还有同步,也就是一个线程完成任务后,交给第二个线程完成。
5、线程访问的全局变量的资源,全局变量属于临界资源。
6、访问临界资源的代码属于临界区。
7、多个线程访问临界资源时无法确定谁先访问谁后访问,属于竞态。
线程互斥之互斥锁
1、一个线程执行任务时其他线程处于等待状态,执行任务后第二个线程再进来执行,但是执行不分先后顺序。
2、互斥锁本质上也是一个临界资源,线程获取到锁资源后执行。
3、定义和初始化互斥锁,线程上锁,解锁,销毁锁资源。
4、临界资源实质上是一个全局变量,所有的线程都共享这个资源。
#include <pthread.h>
pthread_mutex_t fastmutex = PTHREAD_MUTEX_INITIALIZER;静态初始化快速锁
pthread_mutex_t recmutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;静态初始化递归锁
pthread_mutex_t errchkmutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;静态初始化差错锁
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t
*mutexattr);
概念:动态初始化互斥锁。
参数1:互斥锁地址
参数2:互斥锁属性,一般默认属性填NULL
返回值:返回0,不会失败。
int pthread_mutex_lock(pthread_mutex_t *mutex);
功能:给临界区(访问临界资源的代码)上锁
参数:互斥锁地址
返回值:成功返回0,失败返回非0错误码。
int pthread_mutex_unlock(pthread_mutex_t *mutex);
功能:给临界区(访问临界资源的代码)解锁
参数:互斥锁地址
返回值:成功返回0,失败返回非0错误码。
int pthread_mutex_destroy(pthread_mutex_t *mutex);
功能:销毁锁资源
参数:互斥锁地址
返回值:成功返回0,失败返回非0错误码。
线程产生的竞态现象:
#include <myhead.h>
//创建10个线程,每个线程都对一个变量多次+1操作
#define MAX 10
#define N 500000
int k =0;
void *fun()
{
int i;
for(i = 0;i<N;i++)//每个线程都对变量k操作
{
k+=1;
}
}
int main(int argc, const char *argv[])
{
pthread_t tid[MAX];
for(int i = 0;i<MAX;i++)
{
if(pthread_create(&tid[i],NULL,fun,NULL)==-1)//创建10和线程1个线程体函数
{
perror("pthread_create");
return -1;
}
}
sleep(5);
printf("预期结果:5000000\n");//得到的实际结果不是预期结果产生了竟态
printf("实际结果:%d\n",k);
return 0;
}
加入静态互斥锁解决竞态
#include <myhead.h>
//创建10个线程,每个线程都对一个变量多次+1操作
#define MAX 10
#define N 500000
int k =0;
pthread_mutex_t fastmutex = PTHREAD_MUTEX_INITIALIZER;//1、定义并初始化静态互斥锁
void *fun()
{
pthread_mutex_lock(&fastmutex);//2、临界区上锁
int i;
for(i = 0;i<N;i++)//每个线程都对变量k操作
{
k+=1;
}
pthread_mutex_unlock(&fastmutex);//3、临界区解锁
}
int main(int argc, const char *argv[])
{
pthread_t tid[MAX];
for(int i = 0;i<MAX;i++)
{
if(pthread_create(&tid[i],NULL,fun,NULL)==-1)//创建10和线程1个线程体函数
{
perror("pthread_create");
return -1;
}
}
sleep(5);
printf("预期结果:5000000\n");//得到的实际结果不是预期结果产生了竟态
printf("实际结果:%d\n",k);
return 0;
}
加入:动态互斥锁解决静态
#include <myhead.h>
//创建10个线程,每个线程都对一个变量多次+1操作
#define MAX 10
#define N 500000
int k = 0;
pthread_mutex_t fastmutex;//1、定义互斥锁
void *fun()
{
pthread_mutex_lock(&fastmutex);//3、临界区上锁
int i;
for(i = 0;i<N;i++)//每个线程都对变量k操作
{
k+=1;
}
pthread_mutex_unlock(&fastmutex);//4、临界区解锁
}
int main(int argc, const char *argv[])
{
pthread_mutex_init(&fastmutex,NULL);//2、动态初始化互斥锁
pthread_t tid[MAX];
for(int i = 0;i<MAX;i++)
{
if(pthread_create(&tid[i],NULL,fun,NULL)==-1)//创建10和线程1个线程体函数
{
perror("pthread_create");
return -1;
}
}
sleep(5);
printf("预期结果:5000000\n");//得到的实际结果不是预期结果产生了竟态
printf("实际结果:%d\n",k);
return 0;
}

5320

被折叠的 条评论
为什么被折叠?



