一、线程的优点

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

(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. Use weakref module in a cache or mapping

    The weakref module allows the Python programmer to create weak references to objects. In the followi ...

  2. 20151227感知机(perceptron)

    1 感知机 1.1 感知机定义 感知机是一个二分类的线性分类模型,其生成一个分离超平面将实例的特征向量,输出为+1,-1.导入基于误分类的损失函数,利用梯度下降法对损失函数极小化,从而求得此超平面,该 ...

  3. html5 canvas图片马赛克

    <!doctype html> <html> <head> <meta charset="utf-8"> <title> ...

  4. FATFS文件系统

    STM32移植文件系统,操作SD卡,对SD卡进行读写 FATFS文件系统与底层介质的驱动分离开来,对底层介质的操作都要交给用户去实现,它仅仅是提供了一个函数接口而已,函数为空,要用户添加代码.然后 F ...

  5. apache配置虚拟主机后,启动速度慢

    apache配置虚拟主机后,启动速度慢且提示“the requested operation has failed” 可以通过在cmd下启动,来查找问题(命令中的“apache2.2”,是服务名,根据 ...

  6. android 简易时间轴(实质是ListView)

    ListView的应用 1.在很多时候是要用到时间轴的,有些处理的时间轴比较复杂,这里就给出一个比较简单的时间轴,其实就是ListView里面的Item的设计. 直接上代码: ListView,ite ...

  7. 【转】google推出的SwipeRefreshLayout下拉刷新用法

    SwipeRefreshLayout是Google在support v4 19.1版本的library更新的一个下拉刷新组件,实现刷新效果更方便. 使用如下: 1.先下载android-support ...

  8. 字符串左移n位操作

    void reverse(char* str, int begin, int end) { char temp; for( ; begin < end; begin++) { temp = st ...

  9. CloudSTack4.2 查看所有虚拟机API测试

    http://192.168.153.34:8080/ client/api? command=listVirtualMachines &response=json &sessionk ...

  10. Chrome developer tool:本人钟爱的 console、Network 功能简谈

    在最开始时,本人调试查看网页,一直用的是 firefox 的 firebug 插件,并没有使用 chrome 的 developer tool .只不过,在日常生活使用过程中,一直使用的是 chrom ...