线程 线程等待

线程和进程的区别

在操作系统中,进程是提供程序运行资源的最小单位,而线程是调度这些资源的最小单位,也称作该进程的执行流.
在一个进程运行时,它的地址空间和另一个进程是独立的.也就是说他们的资源是独有的,一个进程在正常情况下是看不见另一个进程的资源的(除了进程通信)

而在一个进程内部的多个线程,他们是运行在一个地址空间范围内的,所以它们可以看见和共享 进程 提供的资源

所以操作系统创作一个进程,至少给它分配一个线程(执行流)

Linux下的线程

在Linux下并没有提供关于线程数据结构,但我们知道操作系统给一个进程分配的PCB是task_struct的结构体;

但其实Linux系统下的进程是一种轻量级进程(LWP), 它的task_struct结构体关键字段如下

{
 pid_t pid;
 pid_t tgid;

 struct task_struct *group_leader;

 struct list_ehad thread_group;

}

其中 pid其实是执行流的 ID号,也就是线程的ID号
而 tgid 是这一组的执行流共有的ID号,实际反应的是个进程的ID号

我们调用 系统调用 getpid();时返回的其实是tgid(执行流共有的ID)

当一个进程中只有一个执行流时, 显然pid的值就等于 tgid

就会给我们一种 调用getpid()就是task_struct 中的 pid 错觉

我们可以使用 gettid() 获得线程的 pid;

多线程和进程的优缺点

优点

1.多线程可以实现进程的并发执行
假设一个进程内只有一个执行流,那么它只能串行执行代码.碰到需要I/O等待时会挂起.
如果有多个线程,可以实现一个执行流等待,而另一个执行流执行其他的代码.提高程序的效率
在多处理器的系统上更能体现其优势\

2.线程的切换比进程的切换代价要小

一个进程拥有完整的页表地址映射空间,和上下文
进程切换分两步
1.切换页目录以使用新的地址空间
2.切换内核栈和硬件上下文。

前面已经提到,线程共享进程的内存空间,所以第一步线程是不执行的,显而切换线程的代价要小

还有一点,进程在载入内存中,并不是一次性全部载入内存,而是建立其和虚拟地址的映射,如果在向虚拟地址写入时触发了缺页中断,才将对应的文件载入物理内存中.
所以切换新进程在刚开始运行的会不断的触发缺页中断,效率是很低的

线程的缺点

1 线程是不安全的
因为线程可以同时访问共有资源,那么就会出现访问临界资源带来的数据不一致问题
2. 线程是在进程内部运行的
1. 假如说一个线程崩溃了,操作系统就会杀死进程(回收你的资源),那么所有线程都挂掉了
2. 一个线程调用系统调用,所有线程都会受影响,例如fork(),子进程中就有会有一堆线程在运行,
3. 或者一个线程调用exit(), 进程就退出了
3, 写起来难.. 多线程执行顺序就不是串行的了,要考虑的问题就会变多,有可能程序这次运行是对的,下次就可能出错
这种偶发性bug是最难调试的,当然我们大多情况下写出来的是必发性bug…

Linux下POSIX标准 线程的创建和等待

因为POSXI下的 线程库pthread不是系统默认的库,所以在 编译时需要加上 -l(小L)指明使用的库名称

线程的创建

   #include <pthread.h>

   int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                      void *(*start_routine) (void *), void *arg);

其中第一个参数是线程ID号 ,是个输出型参数 需要提前声明

第二个是创建出现线程的属性, 因为pthread底层也是通过系统调用clone()实现的,

在clone中创建子进程可以对其堆栈大小等进行设置,但是没有特殊情况我们并不关心其属性
所以填NULL就好

第三个参数就是线程创建出来后需要执行的函数, 最后一个参数参数就是执行函数的参数了,参数过多可以传
结构体指针

线程的等待

       #include <pthread.h>

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

       一个线程若果在结束后不进行等待退出
       其分配的资源不会被释放
       所以应该有一个线程等待该进程退出,

    也可使用

  #include <pthread.h>

 int pthread_detach(pthread_t thread); 分离线程,这样当线程退出后会自动回收自己的资源,

有一点应该注意,一个进程在任何时间点只能是join或者detach中的一个状态





测试代码

#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
int retval = 0;
void* pthread_fun1(void* arg)
{
    pthread_t* thread_id = (pthread_t* )arg;
    int cnt = 3;
    while(cnt --)
    {
        printf("thread 1 : %0x cnt %d\n ",thread_id, cnt);
        sleep(1);

    }
    retval = 1;
    return (void*) &retval;
}
void* pthread_fun2(void* arg)
{
    //分离进程2
    pthread_detach(pthread_self());

    pthread_t* thread_id = (pthread_t* )arg;
    int cnt  = 3;
    while(cnt --)
    {
        printf("thread2 : %0x cnt:%d \n",thread_id, cnt);
        sleep(1);
    }
    return (void*) &retval;
}

int main()
{
    pthread_t main_thread, thread1,thread2;
    pthread_create(&thread1,NULL,pthread_fun1,(void *) &thread1);

    pthread_create(&thread2,NULL,pthread_fun2,(void *) &thread2);
    main_thread = pthread_self();
    while(1)
    {
        void  *ret;
        int ret1 = pthread_join(thread1,&ret);
        //阻塞式等待
        int ret2 = pthread_join(thread2,NULL);
        printf("main thread  %0x wait thread1 %0x wait 1 status : %d wait thread2 %0x wait 2 status :%d\n",
                main_thread,thread1, ret1,thread2,ret2);
        printf("%d\n",*(int* )ret);
        sleep(1);
    }























猜你喜欢

转载自blog.csdn.net/kwinway/article/details/80021764