进程VS线程
1、进程是资源分配的最小单位,线程是程序执行的最小单位(资源调度的最小单位)
2、进程有自己的独立地址空间,每启动一个进程,系统就会为它分配地址空间,建立数据表来维护代码段、堆栈段和数据段,这种操作非常昂贵。
而线程是共享进程中的数据的,使用相同的地址空间,因此CPU切换一个线程的花费远比进程要小很多,同时创建一个线程的开销也比进程要小很多。
3、线程之间的通信更方便,同一进程下的线程共享全局变量、静态变量等数据,而进程之间的通信需要以通信的方式(IPC)进行。不过如何处理好同步与互斥是编写多线程程序的难点。
4、但是多进程程序更健壮,多线程程序只要有一个线程死掉,整个进程也死掉了,而一个进程死掉并不会对另外一个进程造成影响,因为进程有自己独立的地址空间。
总而言之,
进程占用资源更多,但是更安全健壮
线程占用资源少,但是相对危险,且通信方便
进程的创建、使用即通信
进程的创建和使用
进程之间的通信(IPC)
使用fork创建的父子进程其实有点类似于直接在命令行运行两个可执行文件,他们是不能通过变量直接进行通信的需要借助集中linux中附带进程间通信工具
这里内容过多,就转载一篇大佬博主的博文吧
进程间的五种通信方式介绍
线程的创建、使用即通信
创建线程
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);
//pthread_t *thread:需要一个句柄,在此函数前定义也给pthread_t t1就好了
//const pthread_attr_t *attr:用于设定一些参数,如果是NULL的话就用默认的参数
//void *(*start_routine) (void *):函数指针,创建线程后会直接进入这个函数执行
//void *arg:线程传参传给函数指针中的void *形参,在函数中经过强制转换后就可以使用了
pthread_t pthread_self(void);
//返回pthread_creat里面的第一个参数,线程的识别码
例子
#include<stdio.h>
#include<pthread.h>
void *func1(void *arg){//这里的arg就是pthread_create中传进来的第四个参数,如果要传入的参数很多就用结构体,创建一个结构体,并赋值好各个参数,然后将其作为参数传入到线程中
static char* ret = "t1 is run out";
printf("son : %ld\n",(unsigned long)pthread_self());
printf("param is %d\n",*((int *)arg));
pthread_exit((void *)ret); //as return
}
int main(){
// int pthread_create(pthread_t * thread,const pthread_attr_t * attr,void * (*start_routine)(void *), void *arg);
int ret;
pthread_t t1;
int param = 100;
char *pret;
ret = pthread_create(&t1,NULL,func1,(void *)¶m);
if(ret == 0){
printf("create t1 success\n");
printf("main : %ld\n",(unsigned long)pthread_self());
}
// int pthread_join(pthread_t th, void **thread_return);
pthread_join(t1,(void**)&pret);
printf("main : %s\n",pret);
return 0;
}
线程互斥锁以及线程的同步
互斥锁的基本概念就是,设定一个空间,里面放置了1把锁,
当一个线程运行到这里就取走一个锁,运行完了回来就放回一个锁,没有取到锁的线程就在这里阻塞
其中需要用到以下的函数
#include <pthread.h>
//创建锁,使用默认设置的时候attr用NULL
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
//销毁锁
int pthread_mutex_destroy(pthread_mutex_t *mutex);
//加锁,加不上去就阻塞
int pthread_mutex_lock(pthread_mutex_t *mutex);
//尝试加锁,失败返回EBUSY,而不阻塞
int pthread_mutex_trylock(pthread_mutex_t *mutex);
//减锁,减不了也阻塞
int pthread_mutex_unlock(pthread_mutex_t *mutex);
// 返回:若成功返回0,否则返回错误编号
以下先创建的t1线程获取了锁,所以必定是先t1再t2
#include<stdio.h>
#include<pthread.h>
int g_data = 0;
pthread_mutex_t mutex;
void *func1(void *arg){
// 加锁
pthread_mutex_lock(&mutex);
printf("t1 : %ld\n",(unsigned long)pthread_self());
// 减锁
pthread_mutex_unlock(&mutex);
}
void *func2(void *arg){
// 加锁
pthread_mutex_lock(&mutex);
printf("t2 : %ld\n",(unsigned long)pthread_self());
// 减锁
pthread_mutex_unlock(&mutex);
}
int main(){
int ret;
char *pret;
pthread_t t1;
pthread_t t2;
// 创造锁
pthread_mutex_init(&mutex,NULL);
ret = pthread_create(&t1,NULL,func1,NULL);
ret = pthread_create(&t2,NULL,func2,NULL);
// 等待两个线程退出
// int pthread_join(pthread_t th, void **thread_return);
pthread_join(t1,NULL);
pthread_join(t2,NULL);
// 销毁锁
pthread_mutex_destroy(&mutex);
return 0;
}
线程条件
线程的条件跟锁是要一起运用的,不能没有锁只有条件
下面将会用到以下几个函数
#include <pthread.h>
//创建条件
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
//销毁条件
int pthread_cond_destroy(pthread_cond_t *cond);
//等待条件
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
//pthread_cond_wait等待条件变为真。如果在给定的时间内条件不能满足,那么会生成一个代表一个出错码的返回变量。
int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, cond struct timespec *restrict timeout);
//pthread_cond_signal函数将唤醒等待该条件的某个线程
int pthread_cond_signal(pthread_cond_t *cond);
//pthread_cond_broadcast函数将唤醒等待该条件的所有进程。
int pthread_cond_broadcast(pthread_cond_t *cond);
例子
#include<stdio.h>
#include<pthread.h>
int g_data = 0;
pthread_mutex_t mutex;
pthread_cond_t cond;
void *func1(void *arg){
while(1){
pthread_cond_wait(&cond,&mutex);//等待条件触发
if(g_data == 3){
printf("t1 : g_data = 3\n");
printf("t1 : run\n");
g_data = 0;
exit(0);
}
sleep(1);
}
}
void *func2(void *arg){
while(1){
pthread_mutex_lock(&mutex);
printf("t2 : %d\n",g_data++);
if(g_data == 3){
pthread_cond_signal(&cond); //触发并发出信息给单个pthread_cond_wait
// pthread_cond_broadcast(&cond);//触发并发出信息给所有pthread_cond_wait
}
pthread_mutex_unlock(&mutex);
sleep(1);
}
}
int main(){
int ret;
int param = 100;
char *pret;
pthread_t t1;
pthread_t t2;
// init lock
pthread_mutex_init(&mutex,NULL);
// init cond
pthread_cond_init(&cond,NULL);
// create pthread t1 & t2
ret = pthread_create(&t1,NULL,func1,(void *)¶m);
ret = pthread_create(&t2,NULL,func2,(void *)¶m);
// int pthread_join(pthread_t th, void **thread_return);
pthread_join(t1,NULL);
pthread_join(t2,NULL);
// destroy cond
pthread_cond_destroy(&cond);
// destroy lock
pthread_mutex_destroy(&mutex);
return 0;
}