一、多线程 VS 多进程

和进程相比,线程有很多优势。在Linux系统下,启动一个新的进程必须分配给它独立的地址空间,建立众多的数据表来维护代码段和数据。而运行于一个进程中的多个线程,他们之间使用相同的地址空间。正是这样,同一进程下的线程之间共享数据空间,数据可以相互使用,并且线程间切换也要更快些,可以更有效的利用CPU。

二、程序设计

[注] 头文件<pthread.h> 编译时要加载动态库 libpthread.a,使用 -lpthread
 
1、创建线程
2、等待线程
3、关闭线程
4、退出清除
 
1、创建线程

int pthread_create(pthread_t *tidp, const pthread_attr_t *attr, void *(*start_rtn)(void), void *arg)

tidp为线程id,是函数分配的值,所以要传一个 pthread_t 的地址。
attr线程属性,通常为空。
start_rtn为线程要执行的函数,返回值为空指针,参数为后面的*arg
若成功则返回0,否则返回出错编号。
 
例:

#include<stdio.h>
#include<pthread.h></p> <p>void *func1(void *arg){ //原函数声明
int i;
for(i=0;i<5;i++){
printf("this is func1! The num is %d\n",*(int*)arg); //将空指针转换为int型指针
sleep(1);
}
}</p> <p>void *func2(int *m){ //自定义类型声明,也可以定义非指针类型,但是在create时会有警告,因为非地址并不能改变传入的值
int i;
for(i=0;i<5;i++){
printf("this is func2! The num is %d\n",*m);
(*m)++;
sleep(1);
}
}</p> <p>int main(){
pthread_t id1,id2;
int num = 5;
int *p = &num;
if(pthread_create(&id1,NULL,(void *)func1,(void *)p) != 0){
printf("thread1 create error!\n");
return -1;
}
if(pthread_create(&id2,NULL,(void *)func2,&num) != 0){
printf("thread2 create error!\n");
return -1;
}
pthread_join(id1,NULL); //等待线程结束  
pthread_join(id2,NULL);
printf("Running complete!\n");
return 0;</p> <p>
}

运行结果:

[fsy@localhost process]$ gcc thC.c -o thC -lpthread -g
[fsy@localhost process]$ ./thC
this is func2! The num is 5
this is func1! The num is 6
this is func2! The num is 6
this is func1! The num is 7
this is func2! The num is 7
this is func1! The num is 8
this is func2! The num is 8
this is func1! The num is 9
this is func2! The num is 9
this is func1! The num is 10
Running complete!
[fsy@localhost process]$

2、等待线程

[注]当调用pthread_create函数时,线程并没有开始执行,主进程应有等待,比如用sleep,或者用更专业的函数:pthread_join

int pthread_join(pthread_t tid, void **rval_ptr)

调用函数可以阻塞调用线程,直到指定的线程终止。
tid为等待退出线程的id,rval_ptr为函数的返回值。是指向指针的指针,可以置空。
 
例:

#include<stdio.h>
#include<pthread.h>
#include<stdlib.h></p> <p>void *func(int *p){
int *num=(int *)malloc(sizeof(int)); //必须动态创建,原因可以参考我动态分配内存的博客
printf("Please input the number: ");
scanf("%d",num);
return (void *)num; //类型是pthread_create的参数规定的
}</p> <p>int main(){
pthread_t pth;
void *a;
if(pthread_create(&pth,NULL,(void *)func,NULL) != 0){
printf("create thread error!\n");
return 1;
}
pthread_join(pth,&a); //指向空指针的指针
printf("get the num from the thread, it's %d\n",*(int *)a);
return 0;
}

3、终止线程

线程终止有以下三种方式:

1、线程从函数中返回
2、线程可以别其他函数终止
3、线程自己调用pthread_exit函数

void pthread_exit(void *rval_ptr)

rval_ptr为线程退出返回值的指针,即函数返回值。

4、退出清除

void pthread_cleanup_push(void (*rtn)(void*), void *arg)

rtn为清除函数,arg是清除函数的参数

void pthread_cleanup_pop(int execute)

当execute 非0时执行清除函数。为0时不执行。

从pthread_cleanup_push的调用点到pthread_cleanup_pop之间的程序段中,如果有终止进程的动作,如调用pthread_exit或异常终止(不包括return),就会执行pthread_cleanup_push()所指定的清理函数。多个嵌套匹配时,就近匹配。
 
例:

#include<stdio.h>
#include<pthread.h></p> <p>void *clean(char *argv){
printf("clean is called by %s\n",argv);
return NULL;
}
void *func1(void *argv){
printf("welcome enter the func1!\n");
pthread_cleanup_push((void*)clean,"the first time call!");
pthread_cleanup_push((void*)clean,"the second time call!");
if(argv){
return (void *)1; //第二次运行将此句注掉
}
pthread_cleanup_pop(0);
pthread_cleanup_pop(1);
return (void *)0;
}</p> <p>void *func2(void *argv){
sleep(1); //两个线程运行先后不确定
printf("welcome enter the func2!\n");
pthread_cleanup_push((void*)clean,"the first time call!");
pthread_cleanup_push((void*)clean,"the second time call!");
if(argv){
pthread_exit(NULL);
}
pthread_cleanup_pop(0);
pthread_cleanup_pop(0);
return (void *)0;
}</p> <p>
int main(){
pthread_t tid1,tid2;
if(pthread_create(&tid1,NULL,(void *)func1,(void *)1) != 0){
printf("thread1 create error!\n");
return 1;
}</p> <p> if(pthread_create(&tid2,NULL,(void *)func2,(void *)1) != 0){
printf("thread2 create error!\n");
return 1;
}
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
return 0;
}

运行结果:

[fsy@localhost process]$ gcc thClean.c -o thclean -lpthread
[fsy@localhost process]$ ./thclean
welcome enter the func1!
welcome enter the func2!
clean is called by the second time call! //此处先2后1
clean is called by the first time call!
[fsy@localhost process]$ vim thClean.c
[fsy@localhost process]$ gcc thClean.c -o thclean -lpthread
[fsy@localhost process]$ ./thclean
welcome enter the func1!
clean is called by the first time call! //second已经被pop
welcome enter the func2!
clean is called by the second time call!
clean is called by the first time call!
[fsy@localhost process]$

Linux 多线程编程实例的更多相关文章

  1. Linux多线程编程实例解析

    Linux系统下的多线程遵循POSIX线程接口,称为 pthread.编写Linux下的多线程程序,需要使用头文件pthread.h,连接时需要使用库libpthread.a.顺便说一下,Linux ...

  2. Linux 多线程编程 实例 2

    编写一个程序,开启3个线程,这3个线程的ID分别为A.B.C,每个线程将自己的ID在屏幕上打印10遍,要求输出结果必须按ABC的顺序显示:如:ABCABC….依次递推. 使用条件变量来实现: #inc ...

  3. Linux 多线程编程 实例 1

    子线程循环 10 次,接着主线程循环 100 次,接着又回到子线程循环 10 次,接着再回到主线程又循环 100 次,如此循环50次,试写出代码. #include <pthread.h> ...

  4. linux下C语言多线程编程实例

    用一个实例.来学习linux下C语言多线程编程实例. 代码目的:通过创建两个线程来实现对一个数的递加.代码: //包含的头文件 #include <pthread.h> #include ...

  5. Linux C语言多线程编程实例解析

    Linux系统下的多线程遵循POSIX线程接口,称为 pthread.编写Linux下的多线程程序,需要使用头文件pthread.h,连接时需要使用库libpthread.a.顺便说一下,Linux ...

  6. Linux多线程编程初探

    Linux线程介绍 进程与线程 典型的UNIX/Linux进程可以看成只有一个控制线程:一个进程在同一时刻只做一件事情.有了多个控制线程后,在程序设计时可以把进程设计成在同一时刻做不止一件事,每个线程 ...

  7. 【操作系统作业-lab4】 linux 多线程编程和调度器

    linux多线程编程 参考:https://blog.csdn.net/weibo1230123/article/details/81410241 https://blog.csdn.net/skyr ...

  8. Linux多线程编程之详细分析

    线程?为什么有了进程还需要线程呢,他们有什么区别?使用线程有什么优势呢?还有多线程编程的一些细节问题,如线程之间怎样同步.互斥,这些东西将在本文中介绍.我见到这样一道面试题: 是否熟悉POSIX多线程 ...

  9. Linux多线程编程阅读链接

    1. 进程与线程的一个简单解释(阮一峰) 2. linux 多线程编程 3. Linux 的多线程编程的高效开发经验 (IBM)

随机推荐

  1. onlyoffice 中文支持稳定操作方法

    网上的都是抄来抄去,不如我这个简单粗暴: 1. 没装过先安装 sudo docker run -i -t -d -p 80:80 onlyoffice/documentserver2 .查看conta ...

  2. Unity3D学习笔记——NGUI之UIGrid

    UIGrid:这个组件可以轻松的让你排列你的组件,并且在运行或是编辑的时候都可以. 效果图如下: 一:使用步骤 1.选择一个panel然后右键Create——Grid 2.为Grid创建几个子Spri ...

  3. PostgreSQL tips

    tip 1 在sql中我们可以设置一个列自增长identity(1,1),但在postgresql中却没有这个关键字定义.但postgresql也有实现相关功能,那就是只需要将该列数据类型标记为ser ...

  4. 【matlab】绘制双三次插值函数曲线

    想要的效果: 编程时要用到分段函数曲线的绘制方法:..+.*(分段条件). 需要注意的是:函数表达式中的乘除和乘方都要加“.”.因为一般的函数都是数在乘变量运算. x=-:; a=-0.5; w=ab ...

  5. ios 2017启动页(Launch Screen Images)、图标(App Icon)尺寸大小

    ios 2017启动页(Launch Screen Images).图标(App Icon)尺寸大小   iPhone Portrait iOS 8,9-Retina HD 5.5 (1242×220 ...

  6. POJ 1861 &amp; ZOJ 1542 Network(最小生成树之Krusal)

    题目链接: PKU:http://poj.org/problem?id=1861 ZJU:http://acm.zju.edu.cn/onlinejudge/showProblem.do?proble ...

  7. jquery 插件 起步代码

    /** * Created by W.J.Chang on 2014/6/25. */ ;(function($) { var methods= { check: function() { retur ...

  8. Kettle 7启动 Spoon.bat 时报错“A Java Exception has occurred.”的解决方法

    最近在研究Kettle 时出现启动时报错“A Java Exception has occurred.”的问题.刚开始没搞明白是什么原因,后来发现是jdk版本的问题.出现这个错误原因是 Kettle ...

  9. 【BZOJ3944/4805】Sum/欧拉函数求和 杜教筛

    [BZOJ3944]Sum Description Input 一共T+1行 第1行为数据组数T(T<=10) 第2~T+1行每行一个非负整数N,代表一组询问 Output 一共T行,每行两个用 ...

  10. coursera 《现代操作系统》 -- 第十周 文件系统(2)

    身份验证 Authentication 知道用户是谁.通过账号密码.Id 这样的识别出来. 访问控制 Permission 知道用户是谁后. 主动控制 记录用户ID和对应的访问权限 --> 记录 ...