一、线程的优点

与传统进程相比,用线程来实现相同的功能有如下优点:

(1)系统资源消耗低。

(2)速度快。

(3)线程间的数据共享比进程间容易的多。

二、多线程编程简单实例

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <pthread.h> void
thread1_routine(void)
{
printf("new thread:thread_id is %u, process_id is %u\n",
pthread_self(), getpid());
}
void
thread2_routine(void)
{
printf("new thread:thread_id is %u, process_id is %u\n",
pthread_self(), getpid());
} int
main(void)
{
pthread_t pt;
printf("old thread:thread_id is %u, process_id is %u\n",
pthread_self(), getpid());
pthread_create(&pt, NULL, (void *)thread1_routine, NULL);
pthread_create(&pt, NULL, (void *)thread2_routine, NULL);
usleep(5);
return(0);
}

运行结果如下(可以看出在同一个进程中有三个不同的线程同时在运行):

三、线程属性

线程属性包括绑定属性、分离属性、堆栈地址、堆栈大小和优先级。其中分离属性、堆栈地址以及堆栈大小的介绍可参考http://www.cnblogs.com/nufangrensheng/p/3522583.html。系统默认的是非邦定、非分离、缺省1M的堆栈、与父进程同样级别的优先级。在pthread_create中,把第二个参数设置为NULL的话,将采用默认的属性配置。

1、绑定属性

线程可以分为用户级线程和内核级线程两种(可参考http://blog.csdn.net/songjinshi/article/details/9042265以及http://www.xuebuyuan.com/1380720.html),而绑定属性正是设置用户级线程和内核级线程之间的关系。

绑定属性分为两种:绑定和非绑定。在绑定属性下,一个用户级线程固定分配给一个内核线程,因为CPU时间片的调度是面向内核线程(轻量级进程)的,因此具有 绑定属性的线程可以保证在需要的时候总有一个内核线程与之对应。在非绑定属性下,用户线程和内核线程的关系不是始终固定的,而是由系统根据实际情况分配的。

2、优先级

四、线程互斥

生产者消费者实例(多线程+互斥量):

#include <stdio.h>
#include <pthread.h>
#include <sched.h> void *producter_f(void *arg);
void *consumer_f(void *arg); int buffer_has_item = 0;
pthread_mutex_t mutex;
int running = 1; int
main(void)
{
pthread_t consumer_t;
pthread_t producter_t; pthread_mutex_init(&mutex, NULL); pthread_create(&producter_t, NULL, (void *)producter_f, NULL); pthread_create(&consumer_t, NULL, (void *)consumer_f, NULL); sleep(1); /* 等待线程创建完毕 */
running = 0;
pthread_join(consumer_t, NULL);
pthread_join(producter_t, NULL);
pthread_mutex_destroy(&mutex); return(0);
} void *
producter_f(void *arg)
{
while(running)
{
if(buffer_has_item < 10) /* 最多允许生产10个 */
{
pthread_mutex_lock(&mutex);
buffer_has_item++;
printf("product, total: %d\n", buffer_has_item);
pthread_mutex_unlock(&mutex);
}
}
} void *
consumer_f(void *arg)
{
while(running)
{
if(buffer_has_item > 0) /* 缓冲区为空时不允许再消费 */
{
pthread_mutex_lock(&mutex);
buffer_has_item--;
printf("consume, total: %d\n", buffer_has_item);
pthread_mutex_unlock(&mutex);
}
}
}

编译运行结果如下:

 

五、线程中使用信号量

(此处使用的信号量是POSIX无名信号量:http://www.cnblogs.com/nufangrensheng/p/3564306.html)

线程的信号量与进程的信号量类似,使用线程的信号量可以高效地完成基于线程的资源计数。信号量实际上是一个非负的整数计数器,用来实现对公共资源的控制。在公共资源增加的时候,信号量的值增加;公共资源消耗的时候,信号量的值减少;只有当信号量的值大于0时,才能允许访问信号量所代表的公共资源。

生产者消费者实例(多线程+信号量):

#include <stdio.h>
#include <pthread.h>
#include <semaphore.h> void *producter_f(void *arg);
void *consumer_f(void *arg); sem_t sem;
int running = 1; int
main(void)
{
pthread_t consumer_t;
pthread_t producter_t; sem_init(&sem, 0, 16); pthread_create(&producter_t, NULL, (void *)producter_f, NULL); pthread_create(&consumer_t, NULL, (void *)consumer_f, NULL); sleep(1);
running = 0;
pthread_join(consumer_t, NULL);
pthread_join(producter_t, NULL);
sem_destroy(&sem); return(0);
} void *
producter_f(void *arg)
{
int semval = 0;
while(running)
{
usleep(1);
sem_post(&sem);
sem_getvalue(&sem, &semval);
printf("product, total: %d\n", semval);
}
} void *
consumer_f(void *arg)
{
int semval = 0;
while(running)
{
usleep(1);
sem_wait(&sem);
sem_getvalue(&sem, &semval);
printf("consume, total: %d\n", semval);
}
}

编译运行如下:

 

更多关于线程的介绍可参考http://www.cnblogs.com/nufangrensheng/p/3518114.html及其后续博文。

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下获取线程TID的方法——gettid()

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

  9. Linux下简易线程池

    线程池简介 线程池是可以用来在后台执行多个任务的线程集合. 这使主线程可以自由地异步执行其他任务.线程池通常用于服务器应用程序. 每个传入请求都将分配给线程池中的一个线程,因此可以异步处理请求,而不会 ...

随机推荐

  1. 一道关于java 类初始化 成员初始化的笔试题的解析

    代码如下: java笔试题public class Mapplication { private static int n; private static Mapplication m1 = new ...

  2. Embedded之memory type

    1 Types of memory 2 Characteristics

  3. win7的centos虚拟机上搭建mysql5.6服务

    1 安装包下载 mysql5.6下载地址: http://dev.mysql.com/downloads/mysql/ 这里选择linux版本: navicat11破解版的下载地址: http://d ...

  4. air for ios

    在 Adobe AIR 中为不同屏幕尺寸的多种设备提供支持 使用Flash Builder 4.5进行多平台游戏开发 手机屏幕触控技术与提升AIR在Android上的触控体验 AIR Native E ...

  5. var隐式类型

    var dogName = "ruiky"; 1.[编译器]会在编译时自动根据值的类型推断这个变量的类型:       2.变量类型不可更改:因为声明的时候已经确定类型了. 3.可 ...

  6. JavaScript 变量、作用域及内存详解

    基本类型值有:undefined,NUll,Boolean,Number和String,这些类型分别在内存中占有固定的大小空间,他们的值保存在栈空间,我们通过按值来访问的. (1)值类型:数值.布尔值 ...

  7. EntityFramework简单例子

    @(编程) 这个例子是用vs2013连接mysql数据库. 1. NuGet安装EF和mysql 略 2. 对象 namespace EFDemo { class Student { public s ...

  8. 摄影初学者挑选相机的常见问题 FAQ

    数码相机一次次降价,越来越多的人加入摄影的行列,照相器材还是一个比较专业的领域,并非简单的参数比一下高低就可以知道好坏,很多朋友往往了解了好久还没弄清孰优孰劣,在购机前踌躇半天拿不定主意,我收集了被问 ...

  9. Windows消息机制要点

    1. 窗口过程     每个窗口会有一个称为窗口过程的回调函数(WndProc),它带有四个参数,分别为:窗口句柄(Window Handle),消息ID(Message ID),和两个消息参数(wP ...

  10. 6 种CSS设置居中的方法

    原文 Demos of each of the methods below by clicking here. Horizontal centering with css is rather easy ...