24多线程

基本概念

线程:进程中的某一个处理流程

一个进程可以有多个线程,进程是线程的父进程

所有线程与父进程共享资源

线程分类

内核态线程

由内核调度程序直接调度,充分发挥多处理器的优势

目前linux系统标准线程库采用内核线程方式实现多线程

用户态线程

一个进程包含多个线程,这些线程从内核调度角度来看只是一个进程,内核把它当一个进程来调度。线程之间调度在用户态进行

用户态线程优点是调度效率高(不需要内核参与调度),缺点是对于多核处理器利用率不高,一个线程阻塞会导致整个线程组阻塞

创建线程

#include<pthread.h>

int  pthread_create(pthread_t *id,  pthread_attr_t  *attr,  void *pFun,  void *args)

参数:

id :      返回线程ID

attr:     线程属性

pFun:  线程调用的函数

args: 线程函数的参数

注意:创建成功返回0,否则返回错误码

线程管理

pthread_exit(void *pRet)             pRet指定线程退出返回值

int  pthread_join(pthread_t  id,  void **pRet)

使主进程等待线程完成后才退出

pRet 获得 pthread_exit 函数调用的返回值,一般为NULL

pthread_self()

线程函数里,获取本线程的线程ID

pthread_getattr_np(pthread_t id, pthread_attr_t *attr)

获取线程属性

线程属性, 调用 init 函数初始化线程属性

pthread_attr_init(pthread_attr_t  *attr)

struct pthread_attr_t {

    int         __detachstate;  

    int         __schedpolicy;

    struct sched_param  __schedparam;

    int          __inheritsched;

    int            __scope;

    size_t    __guardsize;

    int          __stackaddr_set;

    void *    __stackaddr;

    unsigned long int  __stacksize;

}

线程属性详解

__detachstate: 线程分离状态

PTHREAD_CREATE_JOINABLE      可与其他线程连接

PTHREAD_CREATE_DETACHED

设置/获取线程分离状态

int  pthread_attr_setdetachstate(pthread_attr_t *attr,  int  detachstate)

int  pthread_attr_getdetachstate(pthread_attr_t *attr,  int *pdetachstate)

__schedpolicy:    线程调度策略

SCHED_OTHER       系统默认(分时调度),各个优先级任务时间轮换

SCHED_FIFO            实时调度,先到先服务(独占)

SCHED_RR               实时调度,时间片轮转(高优先级轮换)

设置/获取线程调度策略

int pthread_attr_setschedpolicy(pthread_attr_t *attr,  int  policy)

int pthread_attr_getschedpolicy (pthread_attr_t *attr,  int *pPolicy)

__schedparam 线程优先级信息

__schedparam.sched_priority

设置获取线程属性参数

int pthread_attr_setschedparam(pthread_attr_t *attr, struct sched_param  *param)

int pthread_attr_getschedparam(pthread_attr_t *attr, struct sched_param  *param)

对于 SCHED_FIFO    SCHED_RR 调度,设置优先级param.sched_priority

__inheritsched   线程继承性

PTHREAD_INHERIT_SCHED     从父进程继承调度属性

PTHREAD_EXPLICIT_SCHED   不从父进程继承调度属性

设置/获取线程继承性

int pthread_attr_setinheritsched(pthread_attr_t *attr,  int  inheritsched)

int pthread_attr_getinheritsched(pthread_attr_t *attr,  int  *pinheritsched)

__scope      线程作用域

PTHREAD_SCOPE_SYSTEM     系统所有进程间调度

PTHREAD_SCOPE_PROCESS  当前进程间调度

设置/获取线程作用域

int pthread_attr_setscope(pthread_attr_t *attr,  int scope)

int pthread_attr_getscope(pthread_attr_t *attr,  int *pscope)

__stackaddr   线程堆栈地址

__stacksize    线程堆栈大小

获取/设置线程桟

int pthread_attr_setstackaddr(pthread_attr_t *attr,  void * stackaddr)

int pthread_attr_getstackaddr(pthread_attr_t *attr,  void ** stackaddr)

int pthread_attr_setstacksize(pthread_attr_t *attr,  size_t  *stacksize)

int pthread_attr_setstacksize(pthread_attr_t *attr,  size_t  *stacksize)

__guardsize   警戒缓冲区大小

线程桟末尾防止桟溢出的扩展内存大小

设置/获取线程警戒缓冲区

int pthread_attr_getguardsize(pthread_attr_t *attr, size_t  *guardsize)

int pthread_attr_setguardsize(pthread_attr_t *attr, size_t  *guardsize)

无效化线程属性

pthread_attr_destroy(pthread_attr_t *attr)

无效化后, 使用attr 创建线程会失败

退出线程方式

1:  线程指定函数执行完毕

2:  进程退出

3:  线程调用exec函数

4:  线程调用 pthread_exit 函数退出

5:  线程调用 pthread_cancel 终止

pthread_exit(void *pRet)    pRet指定线程退出返回值,可用于pthread_join()

例子:

#define _GNU_SOURCE

#include<stdio.h>

#include<pthread.h>

#include<stdlib.h>

#include<unistd.h>

#include<string.h>

int g_ret;

void* thread()

{

      printf("My thread id %#x ", (int)pthread_self());

      int i = 10;

      while(i--)

      {

           printf("-> %d ", i);

           usleep(1000);

      }

      g_ret = 100;

      pthread_exit(&g_ret);

      return NULL;

}

int create_demo()

{

      pthread_t tid;

      int iRet;

      iRet = pthread_create(&tid, NULL, thread, NULL);

      if (iRet)

      {

           perror("Fail to pthread_create!");

           return iRet;

      }

      printf("Create thread: %#x ",(int)tid);

      int i=5;

      while(i--)

      {

           printf("Main -> %d ", i);

           usleep(1000);

      }

     

      //pthread_join(tid, NULL);

      int *p;

      pthread_join(tid, (void*)&p);//p point to  g_ret;

      printf("Exit code %d ", *p);

      //sleep(1);

      return 0;

}

void* threadn(void* param)

{

      int n = *((int*)param);

     

      int iRet=0;

      int i;

      for (i=0; i<n; i++)

      {

           iRet+=i;

           fprintf(stderr, "thread[%d]->%d ", n, iRet);

           usleep(100*1000);

      }

      printf(" ");

      return NULL;

}

void Test_threadn()

{

      pthread_t tid1, tid2, tid3;

      int x1=20, x2=15, x3=10;

      pthread_create(&tid1, NULL, threadn, (void*)&x1);

      pthread_create(&tid2, NULL, threadn, (void*)&x2);

      pthread_create(&tid3, NULL, threadn, (void*)&x3);

     

      pthread_join(tid1, NULL);

      pthread_join(tid2, NULL);

      pthread_join(tid3, NULL);

      return;

}

typedef struct tagNumArr

{

      int *arr;

      int size;

}N_ARR;

void* largeSort(void *param)

{

      N_ARR stArr;

     

      memcpy(&stArr, param, sizeof(N_ARR));

      /* sort(stArr.arr, stArr.size) */

     

      /* Save(stArr) */

      return NULL;

}

void Test_LargeSort()

{

      int arr[] = {1,3,5,7,9,2,4,6,8,10};

      N_ARR  stArr = {arr, sizeof(arr)/sizeof(arr[0])};

      pthread_t tid;

      pthread_create(&tid, NULL, largeSort, (void*)&stArr);

      //.......

      pthread_join(tid, NULL);

      return;

}

void Print_SelfAttr()

{

      pthread_attr_t attr;

      pthread_t tid = pthread_self();

      pthread_getattr_np(tid, &attr);

      int iDetachState;

      pthread_attr_getdetachstate(&attr, &iDetachState);

      printf("Detach: %s ", iDetachState == PTHREAD_CREATE_DETACHED?"Detached":"Joinable");

      return;

}

void Test_ThreadAttr()

{

      pthread_attr_t attr;

      pthread_attr_init(&attr);//initialized thread attrib

      pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

     

      pthread_t tid;

      pthread_create(&tid, &attr, (void*)Print_SelfAttr, NULL);

      pthread_attr_destroy(&attr);

      pthread_join(tid, NULL);

      return; 

}

int main()

{

      create_demo();

      //Test_threadn();

      //Test_ThreadAttr();

      return 0;

}

注意:

使用gcc –g –Wall main.c –o main 将会出错。

undefined reference to `pthread_create'

undefined reference to `pthread_join'

collect2: error: ld returned 1 exit status

但是使用gcc –g –Wall  -c main.c -o main.o 不会出错。

说明编译过程没问题,而在链接过程出问题。

因此

gcc –g –Wall main.c –o main –lpthread

-l 代表链接到pthread库

Makefile修改:

.PHONY:clean all

SRC=$(wildcard *.c)

BIN=$(SRC:%.c=%)

CPPSRC=$(wildcard *.cpp)

CPPBIN=$(CPPSRC:%.cpp=%)

CC=gcc

CXX=g++

CFLAGS=-g -Wall

CXXFLAGS =-g -Wall -std=c++11

all:$(BIN)  $(CPPBIN)

$(BIN):%:%.c

      $(CC) $(CFLAGS) $^ -o $@ -lpthread

clean:

      rm -fr $(BIN) $(CPPBIN)

原文地址:https://www.cnblogs.com/gd-luojialin/p/9216025.html