什么是线程:

  在一个程序里的一个执行路线就叫做线程(thread),更准确的定义是:线程是“一个进程内部的控制序列”

  一切进程至少都有一个执行线程

进程与线程:

  进程是资源竞争的基本单位

  线程是程序执行的最小单位

  线程会使用进程的全局变量

  线程共享进程数据,但也拥有自己的一部分数据

    线程ID

    程序计数器

    寄存器组

    栈

    errno

  一个进程内部的线程可以共享资源

    代码段

    数据段

    打开文件和信号

单线程和多线程模型如下:

如何从进程往线程中传数据?又如何从线程中将数据传出来呢?

1、使用全局变量,可以将数据传给线程

2、在进程中分配内存,通过pthread_create的第四个参数传给线程

fork和创建新线程的区别:

线程的属性是可以修改的。竞争范围可以修改。

POSIX线程库:

  与线程有关的函数构成了一个完整的系列,绝大多数函数名字都是以“pthread”开头的。

  要使用这些函数库,需要引入头文件<pthread.h>

  链接这些线程函数库时要使用编译器命令的“-lpthread”选项

pthread_create函数:

  原型:int  pthread_create(pthread_t  *thread,  const  pthread_attr_t  *attr,  void *(*start_routine)(void *),  void  *arg)

  功能:创建一个新的线程

  参数:

    thread:返回的线程ID

    attr:设置线程的属性,attr为NULL表示使用默认属性

    start_routine:是一个函数地址,线程启动后要执行的函数

    arg:传给线程启动函数的参数

  返回值:成功返回0,失败返回错误码

错误检查:

  传统的一些函数是成功返回0,失败返回-1,并且对全局变量errno赋值以指示错误

  pthreads函数出错时不会设置全局变量errno(而大部分其他POSIX函数会这样做),而是将错误码通过返回值返回

  pthread同样也提供了线程内的errno变量,以支持其他使用errno的代码,对于pthreads函数的错误,建议通过返回值来判定,因为读取返回值

  要比读取线程内的errno变量的开销更小。

其他线程函数:

进程和线程对比:

进程:

  fork;有pid;有pcb控制块;有僵尸进程;

线程:

  pthread_create;有tid;有tcb控制块;有僵尸线程

线程和进程有一个巨大的区别,就是线程依赖进程,如果进程死了,线程也会死掉。而进程是父进程死了,子进程依旧可以运行。因为进程有自己独立的内存空间。总之,线程依赖于进程的生命周期。

线程示例程序如下:

 #include <unistd.h>
#include <sys/types.h> #include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>
/*
int pthread_create(pthread_t *restrict thread,
const pthread_attr_t *restrict attr,
void *(*start_routine)(void*), void *restrict arg);
*/ void *start_routine(void *arg)
{
int i = ;
printf("I am thread. \n"); for(i = ; i < ; i++)
printf("B");
fflush(stdout); return NULL;
} int main()
{
pthread_t thread;
int i = ; pthread_create(&thread, NULL, start_routine, NULL); for(i = ; i< ; i++)
{
printf("A");
fflush(stdout);
} return ;
}

执行完32行,线程就去执行线程体函数了,34行开始的for循环已经不再属于线程,也就是说线程执行完线程体就返回了,不会执行到34行。

运行结果如下:

我们看到只打印出了AAAAAAAAA,这是因为,进程(主线程)死了之后,线程也就死了,它还没有来得及执行线程体就死了。我们给进程下面加上sleep,如下:

 #include <unistd.h>
#include <sys/types.h> #include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>
/*
int pthread_create(pthread_t *restrict thread,
const pthread_attr_t *restrict attr,
void *(*start_routine)(void*), void *restrict arg);
*/ void *start_routine(void *arg)
{
int i = ;
printf("I am thread. \n"); for(i = ; i < ; i++)
printf("B");
fflush(stdout); return NULL;
} int main()
{
pthread_t thread;
int i = ; pthread_create(&thread, NULL, start_routine, NULL); for(i = ; i< ; i++)
{
printf("A");
fflush(stdout);
} sleep(); return ;
}

结果如下:

我们看到线程成功打印出了数据。

打印全局变量,程序如下:

 #include <unistd.h>
#include <sys/types.h> #include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>
/*
int pthread_create(pthread_t *restrict thread,
const pthread_attr_t *restrict attr,
void *(*start_routine)(void*), void *restrict arg);
*/ int g_num = ; void *start_routine(void *arg)
{
int i = ;
printf("I am thread. \n");
printf("g_num = %d\n", g_num); for(i = ; i < ; i++)
{
printf("B");
fflush(stdout);
} printf("\n"); return NULL;
} int main()
{
pthread_t thread;
int i = ; g_num = ; pthread_create(&thread, NULL, start_routine, NULL); for(i = ; i< ; i++)
{
printf("A");
fflush(stdout);
}
printf("\n");
sleep(); return ;
}

执行结果如下:

多进程打印全局变量程序如下:

 #include <unistd.h>
#include <sys/types.h> #include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>
/*
int pthread_create(pthread_t *restrict thread,
const pthread_attr_t *restrict attr,
void *(*start_routine)(void*), void *restrict arg);
*/ int g_num = ; void *start_routine(void *arg)
{
int i = ;
printf("I am thread. \n");
printf("g_num = %d\n", g_num); for(i = ; i < ; i++)
{
printf("B");
fflush(stdout);
} printf("\n"); return NULL;
} int main()
{
pid_t pid;
int i = ; g_num = ; pid = fork(); if( pid == )
{
printf("I am child \n");
printf("g_num = %d\n", g_num);
for(i = ; i< ; i++)
{
printf("B");
fflush(stdout);
}
printf("\n");
exit();
} for(i = ; i< ; i++)
{
printf("A");
fflush(stdout);
}
printf("\n");
sleep(); return ;
}

结果如下:

获取线程ID的示例:

 #include <unistd.h>
#include <sys/types.h> #include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>
/*
int pthread_create(pthread_t *restrict thread,
const pthread_attr_t *restrict attr,
void *(*start_routine)(void*), void *restrict arg);
*/ int g_num = ; void *start_routine(void *arg)
{
int i = ;
printf("I am thread. \n");
printf("g_num = %d\n", g_num);
printf("thread id = %lu\n", pthread_self()); for(i = ; i < ; i++)
{
printf("B");
fflush(stdout);
} printf("\n"); return NULL;
} int main()
{
pthread_t thread;
int i = ; g_num = ; pthread_create(&thread, NULL, start_routine, NULL); for(i = ; i< ; i++)
{
printf("A");
fflush(stdout);
}
printf("\n");
sleep(); return ;
}

结果如下:

上面的程序中,我们使用sleep等待,让子进程先运行,但是这不是根本的解决办法,我们使用pthread_join等待子线程退出,程序如下:

 #include <unistd.h>
#include <sys/types.h> #include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>
/*
int pthread_create(pthread_t *restrict thread,
const pthread_attr_t *restrict attr,
void *(*start_routine)(void*), void *restrict arg);
*/ int g_num = ; void *start_routine(void *arg)
{
int i = ;
printf("I am thread. \n");
printf("g_num = %d\n", g_num);
printf("thread id = %lu\n", pthread_self()); for(i = ; i < ; i++)
{
printf("B");
fflush(stdout);
} sleep(); printf("\n"); return NULL;
} int main()
{
pthread_t thread;
int i = ; g_num = ; pthread_create(&thread, NULL, start_routine, NULL); for(i = ; i< ; i++)
{
printf("A");
fflush(stdout);
}
printf("\n"); pthread_join(thread, NULL); return ;
}

结果如下:

线程有两种死掉的方法,一个是自杀一个是他杀。

我们先用exit使子线程退出,程序如下:

 #include <unistd.h>
#include <sys/types.h> #include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>
/*
int pthread_create(pthread_t *restrict thread,
const pthread_attr_t *restrict attr,
void *(*start_routine)(void*), void *restrict arg);
*/ int g_num = ; void *start_routine(void *arg)
{
int i = ;
printf("I am thread. \n");
printf("g_num = %d\n", g_num);
printf("thread id = %lu\n", pthread_self()); for(i = ; i < ; i++)
{
printf("B");
fflush(stdout);
} sleep(); printf("\n"); exit();
} int main()
{
pthread_t thread;
int i = ; g_num = ; pthread_create(&thread, NULL, start_routine, NULL); for(i = ; i< ; i++)
{
printf("A");
fflush(stdout);
}
printf("\n"); pthread_join(thread, NULL);
printf("child thread die\n"); return ;
}

结果如下:

我们发现子线程退出后,父进程没有打印出第54行的数据,说明子线程用exit退出后,父进程也挂了,相当于同归于尽。因此,线程退出千万不能用exit。

我们可以使用pthread_exit让线程死掉,程序如下:

 #include <unistd.h>
#include <sys/types.h> #include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>
/*
int pthread_create(pthread_t *restrict thread,
const pthread_attr_t *restrict attr,
void *(*start_routine)(void*), void *restrict arg);
*/ int g_num = ; void *start_routine(void *arg)
{
int i = ;
printf("I am thread. \n");
printf("g_num = %d\n", g_num);
printf("thread id = %lu\n", pthread_self()); for(i = ; i < ; i++)
{
printf("B");
fflush(stdout);
} sleep(); printf("\n"); pthread_exit(NULL);
} int main()
{
pthread_t thread;
int i = ; g_num = ; pthread_create(&thread, NULL, start_routine, NULL); for(i = ; i< ; i++)
{
printf("A");
fflush(stdout);
}
printf("\n"); pthread_join(thread, NULL);
printf("child thread die\n"); return ;
}

执行结果如下:

可以看到第54行打印出来了。

线程他杀就是父进程调用pthread_cancel杀掉子线程,这个很少用。

父进程如果不想等待线程结束,可以让线程脱离这个进程运行,使用pthread_detach函数,程序如下:

 #include <unistd.h>
#include <sys/types.h> #include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>
/*
int pthread_create(pthread_t *restrict thread,
const pthread_attr_t *restrict attr,
void *(*start_routine)(void*), void *restrict arg);
*/ int g_num = ; void *start_routine(void *arg)
{
int i = ;
pthread_detach(pthread_self());
printf("I am thread. \n");
printf("g_num = %d\n", g_num);
printf("thread id = %lu\n", pthread_self()); for(i = ; i < ; i++)
{
printf("B");
fflush(stdout);
} sleep(); printf("\n"); pthread_exit(NULL);
} int main()
{
pthread_t thread;
int i = ; g_num = ; pthread_create(&thread, NULL, start_routine, NULL); for(i = ; i< ; i++)
{
printf("A");
fflush(stdout);
}
printf("\n"); pthread_join(thread, NULL);
printf("child thread die\n"); return ;
}

结果如下:

一般在线程体函数中立即调用pthread_detach函数。

我们编译多线程程序时要加上 -lpthread,使用ldd可以查看程序用了哪些动态库,如下所示:

可以使用nm查看一个库中的函数(符号),如下:

12.2 linux下的线程的更多相关文章

  1. Linux下查看线程数的几种方法汇总

    Linux下查看线程数的几种方法汇总 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Linux下查看某个进程的线程数量 pstree命令以树状图显示进程间的关系(display ...

  2. Linux下Java线程具体监控和其dump的分析使用----分析Java性能瓶颈[张振华-Jack]

    作者:张振华(Jack) 这里对linux下.sun(oracle) JDK的线程资源占用问题的查找步骤做一个小结: linux环境下,当发现java进程占用CPU资源非常高,且又要想更进一步查出哪一 ...

  3. Linux下进程线程,Nignx与php-fpm的进程线程方式

    1.进程与线程区别 进程是程序执行时的一个实例,即它是程序已经执行到课中程度的数据结构的汇集.从内核的观点看,进程的目的就是担当分配系统资源(CPU时间.内存等)的基本单位. 线程是进程的一个执行流, ...

  4. Linux下简单线程池的实现

    大多数的网络服务器,包括Web服务器都具有一个特点,就是单位时间内必须处理数目巨大的连接请求,但是处理时间却是比较短的.在传统的多线程服务器模型中是这样实现的:一旦有个服务请求到达,就创建一个新的服务 ...

  5. 一个Linux下C线程池的实现

    什么时候需要创建线程池呢?简单的说,如果一个应用需要频繁的创建和销毁线程,而任务执行的时间又非常短,这样线程创建和销毁的带来的开销就不容忽视,这时也是线程池该出场的机会了.如果线程创建和销毁时间相比任 ...

  6. linux下的线程池

    什么时候需要创建线程池呢?简单的说,如果一个应用需要频繁的创建和销毁线程,而任务执行的时间又非常短,这样线程创建和销毁的带来的开销就不容忽视,这时也是线程池该出场的机会了.如果线程创建和销毁时间相比任 ...

  7. linux下使用线程锁互斥访问资源

    linux使用线程锁访问互斥资源: 1.线程锁的创建 pthread_mutex_t g_Mutex; 2.完整代码如下 #include <stdio.h> #include <s ...

  8. Linux下的线程

    一.线程的优点 与传统进程相比,用线程来实现相同的功能有如下优点: (1)系统资源消耗低. (2)速度快. (3)线程间的数据共享比进程间容易的多. 二.多线程编程简单实例 #include < ...

  9. Linux下获取线程TID的方法——gettid()

    (转载)http://blog.csdn.net/delphiwcdj/article/details/8476547 如何获取进程的PID(process ID)? 可以使用: #include & ...

随机推荐

  1. neu 1694 Primorial vs LCM 数论

    1694: Primorial vs LCM 时间限制: 4 Sec  内存限制: 128 MB[提交][状态][讨论版] 题目描述 Given N (2<=N<=10^14), what ...

  2. Linux环境下的定时任务(转载)

    今天做了个数据库的备份脚本,顺便系统得学习一下Linux下定时执行脚本的设置.Linux下的定时执行主要是使用crontab文件中加入定制计划来执行,设置比Windows稍微复杂一些(因为没有图形界面 ...

  3. 图片保存到数据库以及C#读取图片

    图片保存到数据库,如果是sqlserver就是Image类型,如果保存到Oracle就是blob类型,在c#中相对应的就是byte[]类型,同时只需要对读出的数据强制转换就行(byte[])objec ...

  4. apktool 打包解包apk的总结

    1) 不需要另外下载 baksmali-2.1.2.jar, apktool.jar 好像都包含了. apktool d zhanqi.xxx.apk -o zhanqi 2) smalidea-0. ...

  5. English trip -- VC(情景课)1 C What's your name?(review)

    Xu言: 今天,阴差阳错又上了一次 VC 1 C的课,不过这次是小班的形式.这次课的教室叫 toronto   [təˈrɒntəʊ]  to ron to (多伦多(加拿大城市))   - -0我还 ...

  6. 关于一致性hash详细

    一致性哈希算法在1997年由麻省理工学院提出的一种分布式哈希(DHT)实现算法,设计目标是为了解决因特网中的热点(Hot spot)问题,初衷和CARP十分类似.一致性哈希修正了CARP使用的简 单哈 ...

  7. ubuntu svn二进制文件

    1. 查找2:04时间的日志文件和position. Ps:这里假设我找到的是 mysql-bin.000065 位置开始为1356. 2  复制最近的几个日志文件,从mysql-bin.000065 ...

  8. The requested URL /phpmyadmin was not found on this server.

    这个报错,我弄了好久,第一次我以为我安装有问题,我就卸载重新安装了,但是在结果还是报这样子的错. 查找phpmyadmin的安装位置输入: sudo dpkg -L phpmyadmin 可以看到很多 ...

  9. FREETEXTBOX

    本文转自http://blog.csdn.net/JOHNCOOLS/archive/2006/04/08/655553.aspx感谢作者们的付出---------------版本: FreeText ...

  10. oracle12c中新能优化新特性之热度图和自动数据优化

    1. Oracle12c热度图和自动数据优化 信息生命周期管理(ILM)是指在数据生命周期内管理它们的策略.依赖于数据的年龄和对应用的业务相关性,数据能被压缩,能被归档或移到低成本的存储上.简言之,I ...