声明:本文内容参考自:
http://fanqiang.chinaunix.net/a4/b8/20010811/0905001105.html Linux下的多线程编程
http://blog.csdn.net/lhf_tiger/article/details/8291984 pthrad_attr_setdetachstate
http://blog.csdn.net/ithomer/article/details/6063067 Linux多线程Pthread学习小结
等大神的博客~具体的不一一列出了
好了,回归正文
Linux系统下的多线程遵循POSIX线程接口,称为pthread
使用多线程的优点:
-
众所周知创建一个线程的开销远比创建一个进程的开销要小的多.
启动一个新的进程必须分配给它独立的地址空间,建立众多的数据表来维护它的代码段、堆栈段和数据段,
这是一种"昂贵"的多任务工作方式。而运行于一个进程中的多个线程,它们彼此之间使用相同的地址空间,
共享大部分数据,启动一个线程所花费的空间远远小于启动一个进程所花费的空间,而且,线程间彼此切换所需的时间也远远小于进程间切换所需要的时间 -
对不同进程来说,它们具有独立的数据空间,要进行数据的传递只能通过通信的方式进行,这种方式不仅费时,而且很不方便。线程则不然,由于同一进程下的线程之间共享数据空间,所以一个线程的数据可以直接为其它线程所用,这不仅快捷,而且方便
-
提高应用程序响应。这对图形界面的程序尤其有意义,当一个操作耗时很长时,整个系统都会等待这个操作,此时程序不会响应键盘、鼠标、菜单的操作,而使用多线程技术,将耗时长的操作(time consuming)置于一个新的线程,可以避免这种尴尬的情况
-
使多CPU系统更加有效。操作系统会保证当线程数不大于CPU数目时,不同的线程运行于不同的CPU上。
-
改善程序结构。一个既长又复杂的进程可以考虑分为多个线程,成为几个独立或半独立的运行部分,这样的程序会利于理解和修改。
pthread_exit():终止当前线程
pthread_join():阻塞当前的线程,直到另外一个线程运行结束
pthread_attr_init():初始化线程的属性
pthread_attr_setdetachstate():设置脱离状态的属性(决定这个线程在终止时是否可以被结合)
pthread_kill():向线程发送一个信号
pthread_mutex_init() 初始化互斥锁
pthread_mutex_lock():占有互斥锁(阻塞操作)
pthread_mutex_trylock():试图占有互斥锁(不阻塞操作)。当互斥锁空闲时将占有该锁;否则立即返回
pthread_mutex_unlock(): 释放互斥锁
pthread_mutex_unlock(): 释放互斥锁
pthread_cond_init():初始化条件变量
pthread_cond_destroy():销毁条件变量
线程的合并与分离:
我们首先要明确的一个问题就是什么是线程的合并。从前面的叙述中读者们已经了解到了,pthread_create()接口负责创建了一个线程。那么线程也属于系统的资源,这跟内存没什么两样,而且线程本身也要占据一定的内存空间。众所周知的一个问题就是C或C++编程中如果要通过malloc()或new分配了一块内存,就必须使用free()或delete来回收这块内存,否则就会产生著名的内存泄漏问题。既然线程和内存没什么两样,那么有创建就必须得有回收,否则就会产生另外一个著名的资源泄漏问题,这同样也是一个严重的问题。那么线程的合并就是回收线程资源了。
int pthread_attr_init(pthread_attr_t *attr);
int pthread_attr_destory(pthread_attr_t *attr);
Linux下的线程有:绑定属性、分离属性、调度属性、堆栈大小属性和满占警戒区大小属性.
既然叫锁,就有加锁和解锁的概念。当线程获得了加锁的资格,那么它将独享这个锁,其它线程一旦试图去碰触这个锁就立即被系统“拍晕”。
从互斥锁的这种行为看,线程加锁和解锁之间的代码相当于一个独木桥,同意时刻只有一个线程能执行。从全局上看,在这个地方,
互斥锁在Linux中的名字是mutex。这个似乎优点眼熟。对,在前面介绍NPTL的时候提起过,但是那个叫futex,是系统底层机制。
int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);
int pthread_mutex_destory(pthread_mutex_t *mutex );
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
pthread_mutex_t counter_lock;
...
...
//初始化
pthread_mutex_init(&counter_lock, NULL);
int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);
int pthread_cond_destory(pthread_cond_t *cond);
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
int pthread_cond_timedwait(pthread_cond_t *cond,pthread_mutex_t *mutex, const timespec *abstime);
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);
对于等待“事件”的接口从其名称中可以看出,一种是无限期等待,一种是限时等待。后者与互斥锁的pthread_mutex_trylock()有些类似,即当等待的“事件”经过一段时间之后依然没有发生,那就去干点别的有意义的事情去。而对于控制“事件”发生的接口则有“单播”和“广播”之说。所谓单播就是只有一个线程会得到“事件”已经发生了的“通知”,而广播就是所有线程都会得到“通知”。对于广播情况,所有被“通知”到的线程也要经过由互斥锁控制的独木桥。
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
pthread_mutex_t counter_lock; //互斥锁
pthread_cond_t counter_nonzero; //条件变量
int counter = 0;
int estatus = -1;
void *decrement_counter(void *argv);
void *increment_counter(void *argv);
//******* 主函数 *******//
int main(int argc, char **argv)
{
printf("counter: %d/n", counter);
pthread_t thd1, thd2;
int ret;
//初始化
pthread_mutex_init(&counter_lock, NULL);
pthread_cond_init(&counter_nonzero, NULL);
ret = pthread_create(&thd1, NULL, decrement_counter, NULL); //创建线程1
if(ret){
perror("del:/n");
return 1;
}
ret = pthread_create(&thd2, NULL, increment_counter, NULL); //创建线程2
if(ret){
perror("inc: /n");
return 1;
}
int counter = 0;
while(counter != 10){
printf("counter(main): %d/n", counter); //主线程
sleep(1);
counter++;
}
pthread_exit(0);
return 0;
}
void *decrement_counter(void *argv)
{
printf("counter(decrement): %d/n", counter);
pthread_mutex_lock(&counter_lock);
while(counter == 0)
pthread_cond_wait(&counter_nonzero, &counter_lock); //进入阻塞(wait),等待激活(signal)
printf("counter--(before): %d/n", counter);
counter--; //等待signal激活后再执行
printf("counter--(after): %d/n", counter);
pthread_mutex_unlock(&counter_lock);
return &estatus;
}
void *increment_counter(void *argv)
{
printf("counter(increment): %d/n", counter);
pthread_mutex_lock(&counter_lock);
if(counter == 0)
pthread_cond_signal(&counter_nonzero); //激活(signal)阻塞(wait)的线程(先执行完signal线程,然后再执行wait线程)
printf("counter++(before): %d/n", counter);
counter++;
printf("counter++(after): %d/n", counter);
pthread_mutex_unlock(&counter_lock);
return &estatus;
}
运行结果:
counter(main): 0
counter(decrement): 0
counter(increment): 0
counter++(before): 0
counter++(after): 1
counter--(before): 1
counter--(after): 0
counter(main): 1
counter(main): 2
counter(main): 3
counter(main): 4
counter(main): 5
counter(main): 6
counter(main): 7
counter(main): 8
counter(main): 9