一、进程与线程的区别

1.进程与线程

UNIX/Linux进程可以看成只有一个控制线程:一个进程在同一时刻只做一件事情。有了多个控制线程后,在程序设计时可以把进程设计成在同一时刻做不止一件事,每个线程各自处理独立的任务。  

进程是程序执行时的一个实例,是担当分配系统资源(CPU时间、内存等)的基本单位。在面向线程设计的系统中,进程本身不是基本运行单位,而是线程的容器。程序本身只是指令、数据及其组织形式的描述,进程才是程序(那些指令和数据)的真正运行实例。

线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。线程包含了表示进程内执行环境必须的信息,其中包括进程中表示线程的线程ID、一组寄存器值、栈、调度优先级和策略、信号屏蔽字、errno常量以及线程私有数据。进程的所有信息对该进程的所有线程都是共享的,包括可执行的程序文本、程序的全局内存和堆内存、栈以及文件描述符。在Unix和类Unix操作系统中线程也被称为轻量级进程(lightweight processes),但轻量级进程更多指的是内核线程(kernel thread),而把用户线程(user thread)称为线程。

"进程——资源分配的最小单位,线程——程序执行的最小单位"

 进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。

2.为什么要使用线程?

总的来说就是:进程有独立的地址空间,线程没有单独的地址空间(同一进程内的线程共享进程的地址空间)。

使用多线程的理由之一是和进程相比,它是一种非常"节俭"的多任务操作方式。我们知道,在Linux系统下,启动一个新的进程必须分配给它独立的地址空间,建立众多的数据表来维护它的代码段、堆栈段和数据段,这是一种"昂贵"的多任务工作方式。而运行于一个进程中的多个线程,它们彼此之间使用相同的地址空间,共享大部分数据,启动一个线程所花费的空间远远小于启动一个进程所花费的空间,而且,线程间彼此切换所需的时间也远远小于进程间切换所需要的时间。据统计,总的说来,一个进程的开销大约是一个线程开销的30倍左右,当然,在具体的系统上,这个数据可能会有较大的区别。

使用多线程的理由之二是线程间方便的通信机制。对不同进程来说,它们具有独立的数据空间,要进行数据的传递只能通过通信的方式进行,这种方式不仅费时,而且很不方便。线程则不然,由于同一进程下的线程之间共享数据空间,所以一个线程的数据可以直接为其它线程所用,这不仅快捷,而且方便。当然,数据的共享也带来其他一些问题,有的变量不能同时被两个线程所修改,有的子程序中声明为static的数据更有可能给多线程程序带来灾难性的打击,这些正是编写多线程程序时最需要注意的地方。

除了以上所说的优点外,不和进程比较,多线程程序作为一种多任务、并发的工作方式,当然有以下的优点:

  • 提高应用程序响应。这对图形界面的程序尤其有意义,当一个操作耗时很长时,整个系统都会等待这个操作,此时程序不会响应键盘、鼠标、菜单的操作,而使用多线程技术,将耗时长的操作(time consuming)置于一个新的线程,可以避免这种尴尬的情况。
  • 使多CPU系统更加有效。操作系统会保证当线程数不大于CPU数目时,不同的线程运行于不同的CPU上。
  • 改善程序结构。一个既长又复杂的进程可以考虑分为多个线程,成为几个独立或半独立的运行部分,这样的程序会利于理解和修改。

二、线程的创建及等待

1.相关API

int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);//创建线程,若成功返回0,否则返回错误编号
pthread_t *restrict tid: pthread_t 是一个自定义的无符号的长整型
const pthread_attr_t *restrict attr:线程的属性
void *(*start_rtn)(void *):干活的线程,调用相关的函数
void *restrict arg:要传递的参数
当pthread_create成功返回时,由tidp指向的内存单元被设置为新创建线程的线程ID。attr参数用于定制各种不同的线程属性,暂可以把它设置为NULL,以创建默认属性的线程。
新创建的线程从start_rtn函数的地址开始运行,该函数只有一个无类型指针参数arg。如果需要向start_rtn函数传递的参数不止一个,那么需要>把这些参数放到一个结构中,然后把这个结构的地址作为arg参数传入。

int pthread_exit(void *rval_ptr);//线程的退出
int pthread_join(pthread_t thread, void **rval_ptr);// 线程的等待,成功返回0,否则返回错误编号
pthread_t pthread_self(void);// 返回:调用线程的ID

2.创建一个线程

void* funct1(void* arg){printf("this a thread:%ld\n",(unsigned long)pthread_self());//%ld,长整型,打印调用线程的IDprintf("param=%d\n",*((int*)arg));//打印传入参数的值
}
int main(){int param=500;pthread_t t1;int ret=pthread_create(&t1,NULL,funct1,(void*)&param);//创建一个线程if(ret == 0){printf("creat thread success!\n");}else{printf("creat thread errno!\n");}printf("man;%ld\n",(unsigned long)pthread_self());//打印主线程IDfor(;;);return 0;
}

3.线程的等待

void* funct1(void* arg){static int ret=10;//这里必须加static,不然会出错printf("this a thread:%ld\n",(unsigned long)pthread_self());//%ld,长整型,打印调用线程的IDprintf("param=%d\n",*((int*)arg));//打印传入参数的值pthread_exit((void*)&ret);//线程的退出
int main(){int param=500;pthread_t t1;int* pret=NULL;int ret=pthread_create(&t1,NULL,funct1,(void*)&param);//创建一个线程if(ret == 0){//判断线程是否创建成功printf("creat thread success!\n");}       else{printf("creat thread errno!\n");}       printf("man;%ld\n",(unsigned long)pthread_self());//打印主线程的ID号int join=pthread_join(t1,(void**)&pret);//等待线程的退出,如果不退出就阻塞在这里,且后面的程序不会执行if(join == 0){//判断是否退出成功printf("exit the thread success!\n");printf("man:ti quit:%d\n",*pret);}       else{printf("exit the thread errno!\n");}       return 0;
} 

4.运行结果

三、线程共享内存代码验证

1.代码验证

int data=0;
void* funct1(void* arg){static char* ret="thread t1:you are a lucky dog";printf("pthread t1:%ld\n",(unsigned long)pthread_self());//打印当前线程号printf("prama=%d\n",*((int*)arg));while(1){printf("data1=%d\n",data++);sleep(1);}pthread_exit((void*)ret);//进程退出
}void* funct2(void* arg){static char* ret="thread t2:you are a single dog";printf("pthread t1:%ld\n",(unsigned long)pthread_self());//打印当前线程号printf("prama=%d\n",*((int*)arg));while(1){printf("data2=%d\n",data++);sleep(1);}pthread_exit((void*)ret);//进程退出
}int main(){pthread_t t1;//线程t1pthread_t t2;//线程t2int prama=590;//要传入的参数int prama2=999;char* pret=NULL;char* pret2=NULL;int ret=pthread_create(&t1,NULL,funct1,(void*)&prama);//创建线程if(ret == 0){printf("create pthread success!\n");}else{printf("creat pthread errno!\n");}int ret2=pthread_create(&t2,NULL,funct2,(void*)&prama2);//创建线程if(ret2 == 0){printf("create pthread2 success!\n");}else{printf("creat pthread2 errno!\n");}while(1){printf("data3=%d\n",data++);sleep(1);}int thread=pthread_join(t1,(void**)&pret);//等待进程退出if(thread == 0){printf("exit t1 thread success!\n");}else{printf("exit t1 thread errno!\n");}int thread2=pthread_join(t2,(void**)&pret2);//等待进程退出if(thread2 == 0){printf("exit t2 thread success!\n");}else{printf("exit t2 thread errno!\n");}printf("main pthread:%ld\n",(unsigned long)pthread_self());printf("ptread t1:%s\n",pret);printf("ptread t2:%s\n",pret2);for(;;);//主线程不退出return 0;
}

2.运行结果

四、线程同步之互斥量上锁与解锁

1.相关API

int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);//初始化锁
int pthread_mutex_destroy(pthread_mutex_t *mutex);//销毁锁
// 返回:若成功返回0,否则返回错误编号
int pthread_mutex_lock(pthread_mutex_t *mutex);//加锁
int pthread_mutex_unlock(pthread_mutex_t *mutex);//解锁
// 返回:若成功返回0,否则返回错误编号

2.上锁与解锁

pthread_mutex_t mutex;//创建锁
void* funct1(void* arg){pthread_mutex_lock(&mutex);//上锁int i;for(i=0;i<5;i++){printf("t1 pthread:%ld\n",(unsigned long)pthread_self());printf("t1 arg=%d\n",*((int*)arg));sleep(2);}pthread_mutex_unlock(&mutex);//解锁
}void* funct2(void* arg){pthread_mutex_lock(&mutex);//上锁printf("t2 pthread:%ld\n",(unsigned long)pthread_self());printf("t2 arg2=%d\n",*((int*)arg));pthread_mutex_unlock(&mutex);//解锁
}int main(){int arg=10;int arg2=101;pthread_t t1;pthread_t t2;pthread_mutex_init(&mutex,NULL);//初始化锁,并设置为默认属性    int ret=pthread_create(&t1,NULL,funct1,(void*)&arg);int ret2=pthread_create(&t1,NULL,funct2,(void*)&arg2);printf("main pthread:%ld\n",(unsigned long)pthread_self());pthread_join(t1,NULL);pthread_join(t1,NULL);pthread_mutex_destroy(&mutex);//销毁锁for(;;);return 0;
}

3.运行结果:

五、死锁情况

1.死锁条件

pthread_mutex_t mutex;
pthread_mutex_t mutex2;void* funct1(void* arg){pthread_mutex_lock(&mutex);sleep(2);pthread_mutex_lock(&mutex2);static char* ret="you are a lucky dog";printf("t1 thread:%ld\n",(unsigned long)pthread_self());printf("t1 arg:%d\n",*((int*)arg));//int pthread_exit(void *rval_ptr);pthread_mutex_unlock(&mutex);pthread_mutex_unlock(&mutex2);pthread_exit((void*)ret);
}void* funct2(void* arg){pthread_mutex_lock(&mutex2);sleep(2);pthread_mutex_lock(&mutex);static char* ret2="you are a single dog";printf("t2 thread:%ld\n",(unsigned long)pthread_self());printf("t2 arg:%d\n",*((int*)arg));pthread_mutex_unlock(&mutex2);pthread_mutex_unlock(&mutex);pthread_exit((void*)ret2);
}int main(){pthread_t t1;pthread_t t2;int arg=100;int arg2=100;
`       char* pret;char* pret2;pthread_mutex_init(&mutex,NULL);pthread_mutex_init(&mutex2,NULL);int ret=pthread_create(&t1,NULL,funct1,(void*)&arg);if(ret == 0){printf("create pthread t1 success!\n");}int ret2=pthread_create(&t2,NULL,funct2,(void*)&arg2);if(ret2 == 0){printf("creat pthread t2 successs!\n");}//int pthread_join(pthread_t thread, void **rval_ptr);int join=pthread_join(t1,(void**)&pret);int join2=pthread_join(t2,(void**)&pret2);printf("main:%ld\n",(unsigned long)pthread_self());printf("pret=%s\n",pret);printf("pret2=%s\n",pret2);pthread_mutex_destroy(&mutex);pthread_mutex_destroy(&mutex2);for(;;);return 0;
}

2.运行结果

六、线程条件实现线程的同步

1.线程同步

//int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);
//int pthread_exit(void *rval_ptr)
//int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);//线程条件等待int data=0;
pthread_mutex_t mutex;
pthread_cond_t cond;//创建条件void* funct1(void* arg){static char* ret="you are a lucky dog";printf("t1 thread:%ld\n",(unsigned long)pthread_self());printf("t1 arg:%d\n",*((int*)arg));static int cnt=0;while(1){pthread_cond_wait(&cond,&mutex);//线程条件等待          printf("FUCK YOU!\n");printf("t1 data:%d\n",data);data=0;sleep(1);if(cnt++ == 10){exit(1);}}
//      pthread_exit((void*)ret);
}void* funct2(void* arg2){static char* ret2="you are a single dog";printf("t2 thread:%ld\n",(unsigned long)pthread_self());printf("t2 arg:%d\n",*((int*)arg2));while(1){printf("t2 phtread:%d\n",data);pthread_mutex_lock(&mutex);data++;if(data == 3){//int pthread_cond_signal(pthread_cond_t *cond);//条件触发pthread_cond_signal(&cond);//条件触发}pthread_mutex_unlock(&mutex);sleep(1);}//pthread_exit((void*)ret2);
}int main(){pthread_t t1;pthread_t t2;int arg=10;int arg2=11;char* pret;char* pret2;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);//条件初始化pthread_create(&t1,NULL,funct1,(void*)&arg);pthread_create(&t2,NULL,funct2,(void*)&arg2);pthread_join(t1,(void**)&pret);pthread_join(t2,(void**)&pret2);printf("pret=%s\n",pret);printf("pret2=%s\n",pret2);pthread_mutex_destroy(&mutex);//int pthread_cond_destroy(pthread_cond_t cond);//条件销毁pthread_cond_destroy(&cond);//销毁条件return 0;
}

2.运行结果

Linux线程编程记录相关推荐

  1. Linux应用编程基础04:Linux线程编程

    目录 1. 线程概念与模型 2. 线程实现方式 2.1 内核级线程 2.2 用户级线程 2.3 组合式线程 3. 线程标识 3.1 概念与实现 3.2 相关函数 3.2.1 pthread_equal ...

  2. 在Linux系统下生产者消费者,Linux线程编程之生产者消费者问题

    前言 本文基于顺序循环队列,给出Linux生产者/消费者问题的多线程示例,并讨论编程时需要注意的事项.文中涉及的代码运行环境如下: 本文假定读者已具备线程同步的基础知识. 一  顺序表循环队列 1.1 ...

  3. 跟我一起做面试题-linux线程编程(2)

    如题所述: 子线程循环 10 次,接着主线程循环 100 次,接着又回到子线程循环 10 次,接着再回到主线程又循环 100 次,如此循环50次,试写出代码. -------------------- ...

  4. Linux线程编程(三)

    3 Resetting scheduling policy for child processes 每个线程都有一个reset-on-fork调度标识.当设置该标识后,使用fork(2)创建的子进程不 ...

  5. linux系统串口设置参数,linux 串口编程记录(一)串口参数设置(示例代码)

    一些常用串口属性的设置方法. 设置流控制 termios_new.c_cflag &= ~CRTSCTS; //不使用流控制 termios_new.c_cflag |= CRTSCTS; / ...

  6. Linux多线程编程---线程间同步(互斥锁、条件变量、信号量和读写锁)

    本篇博文转自http://zhangxiaoya.github.io/2015/05/15/multi-thread-of-c-program-language-on-linux/ Linux下提供了 ...

  7. linux杀死线程函数,Linux线程-pthread_kill

    该函数可以用于向指定的线程发送信号: int pthread_kill(pthread_t threadId,int signal); 如果线程内不对信号进行处理,则调用默认的处理程式,如SIGQUI ...

  8. 【Linux | 系统编程】Linux系统编程(文件、进程线程、进程间通信)

    文章目录 Linux系统编程 文件IO open/close函数 read/write函数 文件描述符 阻塞.非阻塞 fcntl函数 lseek函数 传入传出参数 文件系统 文件存储 文件操作 sta ...

  9. Linux系统编程【文件IO、进程、进程间通信、信号、线程、互斥】

    linux系统编程 个人通过学习,手打了一份48000字的Linux系统编程的笔记,包含了[文件IO.进程.进程间通信.信号.多线程.互斥]等知识点,并给出了大量的代码案例对每个重要的知识点进行了代码 ...

最新文章

  1. hdu5256序列变换(非递减子序列)
  2. Linux 增加对外开放的端口
  3. 机器学习研究与开发平台的选择
  4. leetcode112. 路径总和
  5. 树莓派远程监控的实现
  6. redis单线程为什么还快的个人解释
  7. mysql数据库druid密码加密_Druid数据库密码加密
  8. extjs 按钮小箭头展开panel_汽车按钮都是英文看不懂?视频教你认清车内所有按钮,看完秒懂...
  9. jsessionid 在谷歌一直变_谷歌相册也要收费,这次我全靠这些云盘救命
  10. 水仙花数c语言程序vb,VB编程:求水仙花数
  11. 魔兽世界怀旧服正式服风铃键盘鼠标同步器TBC70级燃烧远征
  12. python计算矩阵的散度_Python Sympy计算梯度、散度和旋度的实例
  13. 抖音培训教程,抖音培训班,抖音培训课程(2019实时更新中) -
  14. python热力图参数_python3.5数据处理——百度地图热力图传值
  15. 【C++】模板进阶 — 模板特化
  16. 深度学习之LSTM案例分析(二)
  17. 老树新芽,在ES6下使用Express
  18. 从用户场景和用户心理角度,看微信读书的社交阅读
  19. 【毕业设计】后端实现——设计数据库并存储数据
  20. Web 智能代码编辑器 WeBuilder 2022

热门文章

  1. c语言10000的阶乘,求10000的阶乘(c语言代码实现)
  2. 怎样让Win7显示桌面
  3. php 进程管理,PHP 进程管理器 PHP-FPM
  4. 浙工大计算机调剂分数线,大量调剂!浙江工业大学发布公告!
  5. 零成本拓客秘籍丨券商玩转社群营销的5个步骤
  6. 需求不变,供给减少,根据基本的供需定律,WiCC的价格将会受投票的影响而上涨。
  7. Flarum: 搭建和部署
  8. 别让这7个常犯的错误毁了你的设计
  9. C语言位运算--获取第i位、清零第i位、赋值第i位
  10. js循环nodelist_js循环nodelist