进程和线程的区别
进程:进程是资源分配的最小单位,是程序执行时的实例,在程序运行时创建。
线程:线程是程序执行的最小单位,调度的基本单位,是进程的一个执行流。
并发和并行的区别
并发:在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行。其中两种并发关系分别是同步和互斥。
同步:指进程间的关系是相互依赖。前一个进程的输出是后一个进程的输入。当前一个进程没有输出时,后一个进程必须等待。
互斥:进程之间相互排斥地使用临界资源(一次仅允许一个进程使用地共享资源)。
并行:指在同一时刻,有多条指令在多个处理器上同时执行。
同步和异步的区别
同步:指进程间的关系是相互依赖。前一个进程的输出是后一个进程的输入。当前一个进程没有输出时,后一个进程必须等待。就是实时处理(如打电话)
异步:指进程间相互独立。执行完函数或方法后,不必阻塞性地等待返回值或消息,只需要向系统委托一个异步过程,那么当系统接收到返回值或消息时,系统会自动触发委托的异步过程,从而完成一个完整的流程。 就是分时处理(如收发短信)。
多线程编程
1.创建新线程
pthread_self函数: 获取线程ID
- pthread_t pthread_self(void); 返回值:成功:0; 失败:无
- 线程ID:pthread_t类型,在Linux下为无符号整数(%lu),当前Linux中可理解为:typedef unsigned long int pthread_t
pthread_create函数 : 创建一个新线程
- int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg)
- 返回值:成功:0; 失败:错误号
- 参数1:传出参数,保存系统为我们分配好的线程ID
- 参数2:通常传NULL,表示使用线程默认属性。若想使用具体属性也可以修改该参数。
- 参数3:函数指针,指向线程主函数(线程体),新创建的线程从start_routine函数的地址开始运行,该函数运行结束,则线程结束。
- 参数4:线程主函数执行期间所使用的参数,有参数时输入参数的地址,如要传多个参数, 可以用结构封装。
-
//创建线程,返回线程序号和ID //Linux编译时加上 -lpthread //因为pthread并非Linux系统的默认库,而是POSIX线程库。在Linux中将其作为一个库来使用,因此加上 -lpthread(或-pthread)以显式链接该库。 //gcc -o more_pthread more_pthread.c -lpthread #include <stdio.h> #include <pthread.h> #include <stdlib.h> #include <unistd.h> void *pth(void * arg); int main(int argc,char *argv[]) { int n,i; pthread_t tid; if(argc==2) { n=atoi(argv[1]); } for(i=0;i<n;i++) { pthread_create(&tid, NULL, pth, (void *)i); } sleep(n); printf("i am main,main_pthread_id = %lu\n",pthread_self()); return 0; } void *pth(void *arg) { int i; i=(int)arg; //i=*((int*)arg); sleep(i); printf("i am %d thread,thread_id = %lu\n",i+1,pthread_self()); return NULL; }
atoi()代表的是ascii to integer,即“把字符串转换成有符号数字”,举例如下:
-
char a="-10"; char b="9"; int c=atoi(a)+atoi(b);
那么计算结果c=-10+9=-1。
-
int main(int argc,char * argv[]),表示的就是argc表示你使用这个程序时,输入的参数的个数,argv[]表示各个参数。
-
默认argc为1,argv[0]为程序名称。如果输入一个参数,则argc为2,argv[0]为程序名称,argv[1]为输入的那个参数。以此可推出,多个输入参数的情况。
-
运行结果
2. 单个线程退出
pthread_exit函数 : 将单个线程退出
- void pthread_exit(void *retval); 参数:retval表示线程退出状态,通常传NULL
//退出线程
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
void *pth(void * arg);
int main(int argc,char *argv[])
{
int n,i;
pthread_t tid;
if(argc==2)
{
n=atoi(argv[1]);
}
for(i=0;i<n;i++)
{
pthread_create(&tid, NULL, pth, (void *)i);
}
sleep(n);
printf("i am main,main_pthread_id = %lu\n",pthread_self());
return 0;
}
void *pth(void *arg)
{
int i;
i=(int)arg;
if(i==3)
{
pthread_exit(NULL); //退出第四个线程
}
sleep(i);
printf("i am %d thread,thread_id = %lu\n",i+1,pthread_self());
return NULL;
}
运行结果
线程中,禁止使用exit函数,会导致进程内所有线程全部退出。
3.等待线程结束
pthread_join函数: 阻塞等待线程退出,获取线程退出状态
- int pthread_join(pthread_t thread, void **retval)
- thread: 线程标识符,即线程ID,标识唯一线程
- retval: 用户定义的指针,用来存储被等待线程的返回值
//回收多个子线程
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
int var=10;
void *pth(void * arg);
int main(int argc,char *argv[])
{
int i;
pthread_t tid[5];
int *ret[5];
for(i=0;i<5;i++)
{
pthread_create(&tid[i], NULL, pth, (void *)i);
}
for(i=0;i<5;i++)
{
pthread_join(tid[i],(void**)&ret[i]);
printf("=======%d ret=%d\n",i,(int)ret[i]);
}
printf("i am main,main_pthread_id = %lu\t var=%d\n",pthread_self(),var);
sleep(i);
return 0;
}
void *pth(void *arg)
{
int i;
i=(int)arg;
sleep(i);
if(i==1)
{
var=20;
printf("var=%d\n",var);
return (void*)var;
}
else if(i==3)
{
var=30;
printf("i am %d pthread,id=%lu,var= %d\n",i+1,pthread_self(),var);
pthread_exit((void *)var);
}
else
{
printf("i am %d pthread,id=%lu,var= %d\n",i+1,pthread_self(),var);
pthread_exit((void *)var);
}
return NULL;
}
运行结果
4.线程分离
pthread_detach函数: 实现线程分离
- int pthread_detach(pthread_t thread); 成功:0;失败:错误号
- 指定该状态,线程主动与主控线程断开关系。线程结束后(不会产生僵尸线程),其退出状态不由其他线程获取,而直接自己自动释放(自己清理掉PCB的残留资源)。网络、多线程服务器常用。
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
void *pth(void * arg);
int main(int argc,char *argv[])
{
int err;
pthread_t tid;
void *tret;
#if 1
pthread_attr_t attr; //通过线程属性来设置游离态(分离态)
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
pthread_create(&tid,&attr,pth,NULL);
#else
pthread_create(&tid,NULL,pth,NULL);
pthread_detach(tid); //让线程分离 ----自动退出,无系统残留资源
#endif
while(1)
{
err=pthread_join(tid,&tret);
printf("thread exit code=%d\n",(int)tret);
printf("========err=%d\n",err);
if(err!=0)
{
fprintf(stderr,"thread join err:%s\n\n",strerror(err));
}
else
{
fprintf(stderr,"thread join err:%s\n\n",(int)tret);
}
sleep(2);
}
return 0;
}
void *pth(void *arg)
{
int n=3;
while(n--)
{
printf("thread count %d\n",n);
sleep(1);
}
return (void *)1;
}