【笔记】【Linux多线程】

一、进程、线程的区别与联系

区别

  • 进程(process)是指在系统中正在运行的一个应用程序,是系统资源分配的基本单位,在内存中有其完备的数据空间和代码空间,拥有完整的虚拟空间地址。一个进程所拥有的数据和变量只属于它自己。

  • 线程(thread)是进程内相对独立的可执行单元,所以也被称为轻量进程(lightweight processes);是操作系统进行任务调度的基本单元。它与父进程的其它线程共享该进程所拥有的全部代码空间和全局变量,但拥有独立的堆栈(即局部变量对于线程来说是私有的)。

  • 进程和线程都具有就绪、阻塞和运行三种基本状态。

联系

  • 一个进程至少拥有一个线程——主线程,也可以拥有多个线程;

  • 一个线程必须有一个父进程;

  • 多个进程可以并发执行;

  • 一个线程可以创建和撤销另一个线程;

  • 同一个进程中的多个线程之间可以并发执行。

二、怎样理解阻塞非阻塞与同步异步的区别?

同步和异步关注的是消息通信机制(synchronous communication/ asynchronous communication)

扫描二维码关注公众号,回复: 1088314 查看本文章
  • 同步,就是在发出一个 ”调用”时,在没有得到结果之前,该调用就不返回。但是一旦调用返回,就得到返回值了。

  • 异步则是相反,”调用“在发出之后,这个调用就直接返回了,所以没有返回结果。换句话说,当一个异步过程调用发出后,调用者不会立刻得到结果。而是在”调用“发出后,”被调用者“通过状态、通知来通知调用者,或通过回调函数处理这个调用。

阻塞和非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态。

  • 阻塞调用是指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。(线程挂起:暂时将该线程停止,让cpu处理其他任务)

  • 非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程。

三、阻塞、休眠、挂起的区别?

  • 阻塞是进程在等待某种资源,但是不能马上得到,,必须等待别的进程释放资源才能继续,属于被动无法得到时间片,内核就切换其它进程运行

  • 休眠一般为主动式的放弃一段CPU时间

  • 挂起是运行时间片到了,内核要调度其它进程运行,被动式的失去CPU

四、pthread函数使用

参考文章:http://blog.csdn.net/lishuhuakai/article/details/12010229

注意:在linux的实现中pthread_t被定义为 “unsigned long int”

1)pthread_create

是类Unix操作系统(Unix、Linux、Mac OS X等)的创建线程的函数。
1、头文件

#include<pthread.h>

2、函数声明

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

3、编译链接参数

-lpthread (或-pthread

因为pthread并非Linux系统的默认库,而是POSIX线程库。在Linux中将其作为一个库来使用,因此加上 -lpthread(或-pthread)以显式链接该库。

4、返回值
若线程创建成功,则返回0。若线程创建失败,则返回出错编号,并且*thread中的内容是未定义的。

  • 返回成功时,由tidp指向的内存单元被设置为新创建线程的线程ID。
  • attr参数用于指定各种不同的线程属性。
  • 新创建的线程从start_rtn函数的地址开始运行,
  • 该函数只有一个万能指针参数arg,如果需要向start_rtn函数传递的参数不止一个,那么需要把这些参数放到一个结构中,然后把这个结构的地址作为arg的参数传入。

2)pthread_join

 用来等待一个线程的结束,线程间同步的操作。

1、头文件 :

#include <pthread.h>

2、函数定义:

int pthread_join(pthread_t thread, void **retval);

3、描述 :
pthread_join()函数,以阻塞的方式等待thread指定的线程结束。当函数返回时,被等待线程的资源被收回。如果线程已经结束,那么该函数会立即返回。并且thread指定的线程必须是joinable的。

4、参数 :
- thread: 线程标识符,即线程ID,标识唯一线程。
- retval: 用户定义的指针,用来存储被等待线程的返回值。

5、返回值 :
0代表成功。 失败,返回的则是错误号。

在Linux中,默认情况下是在一个线程被创建后,必须使用此函数对创建的线程进行资源回收,但是可以设置Threads attributes来设置当一个线程结束时,直接回收此线程所占用的系统资源,详细资料查看Threads attributes。

在Linux中,新建的线程并不是在原先的进程中,而是系统通过一个系统调用clone()。该系统调用copy了一个和原先进程完全一样的进程,并在这个进程中执行线程函数。不过这个copy过程和fork不一样。 copy后的进程和原先的进程共享了所有的变量,运行环境。这样,原先进程中的变量变动在copy后的进程中便能体现出来。

可以通过pthread_join()函数来使主线程阻塞等待其他线程退出,这样主线程可以清理其他线程的环境。但是还有一些线程,更喜欢自己来清理退出的状态,他们也不愿意主线程调用pthread_join来等待他们。我们将这一类线程的属性称为detached。

如果我们在调用pthread_create()函数的时候将属性设置为NULL,则表明我们希望所创建的线程采用默认的属性,也就是joinable。如果需要将属性设置为detached,则参考下面的例子:

void*start_run(void*arg)
{
//dosomework
}

intmain()
{
pthread_t thread_id;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
pthread_create(&thread_id,&attr,start_run,NULL);
pthread_attr_destroy(&attr);
sleep(5);
exit(0);
}

3)pthread_detach

创建一个线程默认的状态是joinable, 如果一个线程结束运行但没有被join,则它的状态类似于进程中的Zombie Process,即还有一部分资源没有被回收(退出状态码),所以创建线程者应该pthread_join来等待线程运行结束,并可得到线程的退出代码,回收其资源(类似于wait,waitpid)

但是调用pthread_join(pthread_id)后,如果该线程没有运行结束,调用者会被阻塞,在有些情况下我们并不希望如此,比如在Web服务器中当主线程为每个新来的链接创建一个子线程进行处理的时候,主线程并不希望因为调用pthread_join而阻塞(因为还要继续处理之后到来的链接),
这时可以在子线程中加入代码

pthread_detach(pthread_self())

或者父线程调用

pthread_detach(thread_id)(非阻塞,可立即返回)

这将该子线程的状态设置为detached,则该线程运行结束后会自动释放所有资源。

参考文章:
[1] 关于pthread里面一些函数的使用心得!

                                                            @本文作者:LeatherWang

猜你喜欢

转载自blog.csdn.net/hzwwpgmwy/article/details/68483585