设为首页 加入收藏

TOP

linux 线程基础(一)
2019-06-17 12:08:26 】 浏览:212
Tags:linux 线程 基础

线程基础函数

查看进程中有多少个线程,查看线程的LWP

ps -Lf 进程ID(pid)

执行结果:LWP列

y:~$ ps -Lf 1887
UID        PID  PPID   LWP  C NLWP STIME TTY      STAT   TIME CMD
ys        1887  1341  1887  0    3 14:57 tty2     Sl     0:00 /usr/lib/ibus/ibus
ys        1887  1341  1889  0    3 14:57 tty2     Sl     0:00 /usr/lib/ibus/ibus
ys        1887  1341  1890  0    3 14:57 tty2     Sl     0:00 /usr/lib/ibus/ibus

线程共享的资源:

注意:信号和线程最好不要一起使用。又用信号又用多线程的架构不太合理。

  • 文件描述符表
  • 信号的处理方式
  • 当前工作目录
  • 用户ID和组ID
  • 内存地址空间(.text/.data/.bss/heap/共享库,栈区(stack)不共享)

非线程共享的资源:

  • 线程ID

  • 处理器现场和栈指针(内核栈)

  • 独立的栈空间(用户空间栈)

  • errno变量

    • 所以不能用函数perrno打印错误信息了。

    • 使用strerror函数打印错误信息

      #include <string.h>
      char *strerror(int errnum);
      • errnum:errno
  • 阻塞信号集合

  • 调度优先级

现场优,缺点

  • 优点:1,提高程序并发性。2,开销小。3,数据通信,共享方便
  • 缺点:1,因为使用的时库函数,所以不太稳定。2,调试,编写困难。3,对信号支持不好。

进程和线程都是通过系统函数clone创建的。

每个线程有自己独立的PCB

pcb:进程控制块结构体:/usr/src/linux-headers-4.15.0-29/include/linux/sched.h

  • 进程id:系统中每个进程有唯一的id,在c语言中用pid_t类型表示,是个非负整数。

  • 进程状态:就绪,运行,挂起,停止等状态

  • 描述虚拟地址空间的信息

  • 描述控制终端的信息

  • 进程执行时的当前工作目录(current working directory)

  • umask掩码

  • 文件描述符表,包含很多指向file结构体的指针

  • 和信号相关的信息

  • 用户id和组id

  • 会话(session)和进程组

  • 进程可以使用的资源上限(Resource Limit)

    用【ulimit -a】查看:

    ys@ys:~$ ulimit -a
    core file size          (blocks, -c) 0
    data seg size           (kbytes, -d) unlimited
    scheduling priority             (-e) 0
    file size               (blocks, -f) unlimited
    pending signals                 (-i) 7743
    max locked memory       (kbytes, -l) 16384
    max memory size         (kbytes, -m) unlimited
    open files                      (-n) 1024
    pipe size            (512 bytes, -p) 8
    POSIX message queues     (bytes, -q) 819200
    real-time priority              (-r) 0
    stack size              (kbytes, -s) 8192
    cpu time               (seconds, -t) unlimited
    max user processes              (-u) 7743
    virtual memory          (kbytes, -v) unlimited
    file locks                      (-x) unlimited

pthread_create函数:创建一个线程,并开始执行这个线程

#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                          void *(*start_routine) (void *), void *arg);
  • thread:线程的ID
  • attr:线程的属性,一般不使用
  • start_routine:函数指针
  • arg:start_routine函数的参数
  • 返回值:成功返回0;失败返回errno

编译的时候要加【-lpthread】

pthread_self函数:得到线程的id

#include <pthread.h>
pthread_t pthread_self(void);

例子:得到主线程的ID和子线程的ID。注意要sleep1秒,不睡的话,主线程就先结束了,所以子线程里的打印打不出来。

#include <pthread.h>
#include <unistd.h>
#include <stdio.h>

void * thr(void* args){
  printf("in thread %d, %lu\n", getpid(), pthread_self());
}

int main(){
  pthread_t tid;
  pthread_create(&tid, NULL, thr, NULL);
  printf("in main thread %d, %lu\n", getpid(), pthread_self());
  sleep(1);
  return 0;
}

pthread_exit函数:终止线程

#include <pthread.h>
void pthread_exit(void *retval);
  • retval:线程的返回值

改进上面的例子,用pthread_exit代替sleep

#include <pthread.h>
#include <unistd.h>
#include <stdio.h>

void * thr(void* args){
  printf("in thread %d, %lu\n", getpid(), pthread_self());
  //exit(1);//不要在子线程里调用此函数,调用的结果是把整个进程终止了。
  //return NULL;//可以使用
  //pthread_exit(NULL);//可以使用
}

int main(){
  pthread_t tid;
  pthread_create(&tid, NULL, thr, NULL);
  printf("in main thread %d, %lu\n", getpid(), pthread_self());
  //sleep(1);
  pthread_exit(NULL);
  return 0;
}

终止线程时的注意事项

  • 要使用pthread_exit函数,不能使用exit函数
  • 也可以使用return,但是在主线程里使用return的话,就把进程终止了。
  • exit是推出进程,所以不要在线程函数里调用exit函数

pthread_join函数:阻塞等待回收线程资源,其实也是等待线程结束,所以是阻塞的函数,线程不执行完,pthread_join就一直处于阻塞状态,类似wait函数(回收子进程的函数,也是阻塞的)。并且它的第二个参数是可以接收线程的返回值的。

线程不回收也会变成僵尸线程,线程里也有PCB资源,也要回收。

#include <pthread.h>
int pthread_j
首页 上一页 1 2 3 下一页 尾页 1/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Linux 读写锁 下一篇C语言开发中常见报错的解决方案

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目