前面章节中介绍了进程。从这一章开始介绍线程。进程和线程的差别是什么呢:

进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位. 
线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源.

进程和线程的主要差别在于它们是不同的操作系统资源管理方式。进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。 
1) 简而言之,一个程序至少有一个进程,一个进程至少有一个线程. 
2) 线程的划分尺度小于进程,使得多线程程序的并发性高。 
3) 另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。 
4) 线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。 
5) 从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。 
4.优缺点 
线程和进程在使用上各有优缺点:线程执行开销小,但不利于资源的管理和保护;而进程正相反。同时,线程适合于在SMP机器上运行,而进程则可以跨机器迁移。

用一个比喻来形容进程和线程。一个工厂里面是由多个车间组成。进程就好比工厂的车间。它代表CPU所能处理的单个任务。但是一个车间里可以有多个工人,他们协同完成车间里面的任务。这些工人就可以看做是线程。因此一个进程里面可以包含多个线程。

车间里面的空间都是工人们共享的,这就代表一个进程的内存空间是共享的。每个线程都可以使用这些共享内存。

但是有可能车间里的某个房间空间有限,只能容纳一个人,比如厕所,里面有人的时候其他人就不能进去,这就代表线程使用某些共享内存的时候,其他线程必须等它结束才能使用这块内存。

为了防止其他人进入房间,就是在房间上加一把锁,先到的人锁上门,后到的人看到上锁,就在门口排队。等锁打开再进去,这就是互斥锁,防止多个线程同时读写某一个块内存区域。

还有些房间可以容纳n个人,如果人数大于n,多出来的人只能在外面等着,就好比某些内存只能给固定数目的线程使用。解决的办法就是在门口挂n把钥匙,进入的人取一把钥匙,出来的时候再把钥匙挂回原处。后到的人发现钥匙架空了就知道必须在门口排队等待。这种做法就叫做信号量。用来保证多个线程不会互相冲突。

下面来看下线程的具体用法:

就像每个进程有一个进程ID一样,每个线程也有一个线程ID。和进程ID在整个系统中是唯一的不同,线程ID只有在它所属的进程上下文中才有意义

线程可以通过pthread_self函数来获得自身的线程ID

#include <pthread.h>

pthread_t pthread_self(void);

当一个程序启动时,就有一个进程被操作系统创建,与此同时一个线程也立刻运行,这个线程就是程序的主线程。如果需要再创建子线程,那么创建的线程就是这个主线程的子线程。主线程把新的作业放到一个工作队列中,主线程不允许每个线程任意处理从队列顶端取出的作业,而是由主线程控制作业的分配。

线程创建:

#include <pthread.h>

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

start_rtn: 新创建的线程从start_rtn函数的地址开始运行,该函数只有一个无类型指针参数arg。如果需要向start_rtn函数传递的参数有一个以上,那么需要把这些参数放到一个结构中,然后把这个结构的地址作为art参数传入

来看一个实际的代码:

#include <stdio.h>

#include <stdlib.h>

#include "func.h"

#include <pthread.h>

#include <unistd.h>

#include <windows.h>

void printids(const char *s){

pid_t pid;

pthread_t tid;

pid=getpid();

tid=pthread_self();

printf("%s pid %lu tid %lu (0x%lx)\n",s,(unsigned
long)pid,(unsigned long)tid,(unsigned long)tid);

}

void *thr_fn(void *arg){

printids("new thread:");

return((void *)0);

}

pthread_t ntid;

int main()

{

int err;

err=pthread_create(&ntid,NULL,thr_fn,NULL);

printids("main thread:");

Sleep(1);

return 0;

}

运行如下:可以看到两个线程的PID都是一样的,不同的是tid

那么线程什么时候退出呢,单个线程有3种方式退出,因此可以在不终止整个进程的情况下,停止它的控制流

1 线程可以简单地从启动例程中返回,返回值是线程的退出码

2 线程可以被同一进程的其他线程取消

3 线程调用pthread_exit

来看下进程中的其他线程如何来取消线程,这就需要用到pthread_join(pthread_t thread, void **rval_ptr)

运行后调用线程一直阻塞,直到指定的线程调用pthread_exit, 退出或者返回

#include <stdio.h>

#include <stdlib.h>

#include "func.h"

#include <pthread.h>

#include <unistd.h>

#include <windows.h>

void *thr_fn2(void *arg){

printf("thread2 exiting\n");

return((void *)2);

}

void *thr_fn1(void *arg){

printf("thread1 returning\n");

return((void *)1);

}

int main()

{

pthread_t tid1,tid2;

void *tret;

pthread_create(&tid1,NULL,thr_fn1,NULL);

pthread_create(&tid2,NULL,thr_fn2,NULL);

pthread_join(tid1,&tret);

printf("thread1 exit code %ld\n",(long)tret);

pthread_join(tid2,&tret);

printf("thread2 exit code %ld\n",(long)tret);

return 0;

}

运行结果:

linux c编程:线程创建的更多相关文章

  1. Linux多线程编程——线程的创建与退出

    POSIX线程标准:该标准定义了创建和操纵线程的一整套API.在类Unix操作系统(Unix.Linux.Mac OS X等)中,都使用Pthreads作为操作系统的线程.Windows操作系统也有其 ...

  2. Linux系统编程——线程私有数据

    在多线程程序中.常常要用全局变量来实现多个函数间的数据共享.因为数据空间是共享的,因此全局变量也为全部线程共同拥有. 測试代码例如以下: #include <stdio.h> #inclu ...

  3. linux系统编程--线程

    安装线程man page,命令:sudo apt-get install manpages-posix-dev 线程概念 什么是线程 LWP:light weight process 轻量级的进程,本 ...

  4. Unix 环境高级编程---线程创建、同步、

    一下代码主要实现了linux下线程创建的基本方法,这些都是使用默认属性的.以后有机会再探讨自定义属性的情况.主要是为了练习三种基本的线程同步方法:互斥.读写锁以及条件变量. #include < ...

  5. Linux 多线程编程--线程退出

    今天分析项目中进程中虚存一直增长问题,运行10个小时虚存涨到121G ,RSS占用为16G 非常恐怖. Valgrind测试无内存泄漏. 内存32G 64bit系统信息如下: Linux线程使用方式是 ...

  6. Linux多任务编程——线程

    线程基础 △ 由于进程的地址空间是私有的,因此在进行上下文切换时,系统开销比较大 △ 在同一个进程中创建的线程共享该进程的地址空间 △ 通常线程值得是共享相同地址空间的多个任务 △ 每个线程的私有这些 ...

  7. linux系统编程--线程同步

    同步概念 所谓同步,即同时起步,协调一致.不同的对象,对“同步”的理解方式略有不同. 如,设备同步,是指在两个设备之间规定一个共同的时间参考: 数据库同步,是指让两个或多个数据库内容保持一致,或者按需 ...

  8. LInux多线程编程----线程特定数据的处理函数

    1.pthread_key_t和pthread_key_create() 线程中特有的线程存储, Thread Specific Data .线程存储有什么用了?他是什么意思了?大家都知道,在多线程程 ...

  9. Linux系统编程 —线程属性

    在之前的章节中,我们在调用pthread_create函数创建线程时,第二个参数(即线程属性)都是设为NULL,即使用默认属性.一般情况下,使用默认属性已经可以解决我们开发过程中的大多数问题. 但是, ...

  10. Linux系统编程 —线程同步概念

    同步概念 同步,指对在一个系统中所发生的事件之间进行协调,在时间上出现一致性与统一化的现象. 但是,对于不同行业,对于同步的理解略有不同.比如:设备同步,是指在两个设备之间规定一个共同的时间参考:数据 ...

随机推荐

  1. [Angular] ngPlural

    The usecase is very simple: <div [ngPlural]="items.length"> <ng-template ngPlural ...

  2. 快速构建大数据存储分析平台-ELK平台安装

    一.概述 ELK是由Elastic公司开发的Elasticsearch.Logstash.Kibana三款开源软件的缩写(但不限于这三款软件). 为什么使用ELK? 在目前流行的微服务架构中,一个大型 ...

  3. DNS主从服务器

    一.目的: 我们知道,DNS服务器在网络服务中可能出现故障当机等状况,会导致DNS服务瘫痪,显然在实际的网络应用中我们不希望出现这种状况,所有我们就要配置从 服务器来在主DNS服务器出现故障时代替他来 ...

  4. 根域名服务器 根服务器一般指根域名服务器 (DNS)

    Why There Are Only 13 DNS Root Name Servers -------------------------------------------------------- ...

  5. 了解.net mvc实现原理ActionResult/View

    了解.net mvc实现原理ActionResult/View 上一篇了解了请求至Controller的Action过程,这篇继续看源码处理Action收到请求数据再返回ActionResult到Vi ...

  6. PHP接收和发送XML数据(json也通用)

    一.接收xml数据, 使用php://input,代码如下: <?php $xmldata=file_get_contents("php://input"); $data=s ...

  7. Java中的equals方法和自定义比较器

    Object中的equals()方法默认是按地址比较,而不按内容进行比较, public boolean equals(Object obj) { return (this == obj); } 在S ...

  8. C# 接口中的索引器

    索引器可在 接口(C# 参考) 上声明.接口索引器的访问器与类索引器的访问器具有以下方面的不同: 接口访问器不使用修饰符. 接口访问器没有体. 因此,访问器的用途是指示索引器是读写.只读还是只写.以下 ...

  9. spring 事件驱动模型简介

    事件驱动模型简介 事件驱动模型也就是我们常说的观察者,或者发布-订阅模型:理解它的几个关键点: 首先是一种对象间的一对多的关系:最简单的如交通信号灯,信号灯是目标(一方),行人注视着信号灯(多方): ...

  10. File 的基本操作

    package xinhuiji_day07; import java.io.File;import java.io.IOException; public class FileTest { /**  ...