Linux下多线程编程实例解析

来源:互联网 发布:DNS服务的端口号是什么 编辑:程序博客网 时间:2024/06/06 18:51

提到线程,不得不让人想起进程,所以还是先写下进程与线程的区别吧!
一、进程与线程的区别
进程是程序执行的一个实例,进程有其自己独立的地址空间。一个线程可以含有多个线程,这也是为了提高系统资源利用率,线程的引入有其必然的优势,线程有自己的堆栈。记得操作系统的书籍上有一句经典的话:进程——资源分配的最小单位,线程——程序执行的最小单位。一个通俗的比喻:进程就像一个人,而线程就好像人体内协调工作的各个组织部分,比如血液循环,人的呼吸,心脏的跳动,他们协同工作,共用人体(进程独立的资源空间)。

二、线程操作的基本函数
1、创建线程函数

#include <pthread.h>int pthread_create(pthread_t *restrict tidp,                  const pthread_attr_t *restrict attr,                   void *(*start_rtn)(void),                    void *restrict arg);

成功创建返回0,返回其他值出错。
tidp:指向线程标识符的指针。
attr:设置线程属性。
start_trn:线程运行函数的起始地址。
arg:运行函数的参数。

2、线程属性函数

#include <pthread.h>int pthread_attr_init(pthread_attr_t *attr);//对线程属性进行初始化。int pthread_attr_destroy(pthread_attr_t *attr);//去除线程的初始化属性。

若成功返回0,失败返回-1。
attr:线程属性变量。
调用pthread_attr_init()函数后,attr中所包含的就是系统支持的线程所有属性的默认值。pthread_attr_destroy()去除attr中的属性。线程属性结构如下:
typedef struct
{
int detachstate; 线程的分离状态
int schedpolicy; 线程调度策略
structsched_param schedparam; 线程的调度参数
int inheritsched; 线程的继承性
int scope; 线程的作用域
size_t guardsize; 线程栈末尾的警戒缓冲区大小
int stackaddr_set;
void* stackaddr; 线程栈的位置
size_t stacksize; 线程栈的大小
}pthread_attr_t;

(1)线程的分离状态
有一个函数可以对线程的分离状态进行控制。

#include <pthread.h>int pthread_attr_getdetachstate(const pthread_attr_t *attr,int *detachstate);//获取线程的分离状态int pthread_attr_setdetachstate(pthread_attr_t *attr,intdetachstate);//设置线程的分离状态

若成功返回0,若失败返回-1。
attr:线程属性变量。
detachstate,intdetachstate: 线程的分离状态属性。detachstate可以设置为PTHREAD_CREATE_DETACHED(分离状态启动线程),PTHREAD_CREATE_JOINABLE(正常启动线程)。

线程的分离状态决定一个线程以什么样的方式来终止自己。在默认情况下线程是非分离状态的,这种情况下,原有的线程等待创建的线程结束。只有当pthread_join()函数返回时,创建的线程才算终止,才能释放自己占用的系统资源。
而分离线程不是这样子的,它没有被其他的线程所等待,自己运行结束了,线程也就终止了,马上释放系统资源。程序员应该根据自己的需要,选择适当的分离状态。所以如果我们在创建线程时就知道不需要了解线程的终止状态,则可以pthread_attr_t结构中的detachstate线程属性,让线程以分离状态启动。

(2)线程的继承

#include <pthread.h>int pthread_attr_getinheritsched(const pthread_attr_t*attr,int *inheritsched);//获取线程的继承性int pthread_attr_setinheritsched(pthread_attr_t *attr,intinheritsched);//设置线程的继承性

若成功返回0,若失败返回-1。
attr: 线程属性变量。
inheritsched: 线程的继承性。

继承性决定调度的参数是从创建的进程中继承还是使用在schedpolicy和schedparam属性中显式设置的调度信息。线程不为inheritsched指定默认值,因此如果你关心线程的调度策略和参数,必须先设置该属性。
继承性的可能值是PTHREAD_INHERIT_SCHED(表示新线程将继承创建线程的调度策略和参数)和PTHREAD_EXPLICIT_SCHED(表示使用在schedpolicy和schedparam属性中显式设置的调度策略和参数)。
如果需要显式的设置一个线程的调度策略或参数,那么就必须在设置之前将inheritsched属性设置PTHREAD_EXPLICIT_SCHED。

(3)线程的调度策略

#include<pthread.h>int pthread_attr_getschedpolicy(const pthread_attr_t*attr,int *policy);//获取线程的调度策略int pthread_attr_setschedpolicy(pthread_attr_t *attr,int policy);//设置线程的调度策略

若成功返回0,若失败返回-1。
attr:线程属性变量指针。
policy:调度策略。其中有如下调度策略。

SCHED_FIFO(先进先出):允许一个线程运行直到有更高优先级的线程准备好,或者直到它自愿阻塞自己。在SCHED_FIFO调度策略下,当有一个线程准备好时,除非有平等或更高优先级的线程已经在运行,否则它会很快开始执行。
SCHED_RR(轮循):如果有一个SCHED_RR策略的线程执行了超过一个固定的时期(时间片间隔)没有阻塞,而另外的SCHED_RR或SCHBD_FIFO策略的相同优先级的线程准备好时,运行的线程将被抢占以便准备好的线程可以执行。
当有SCHED_FIFO或SCHED_RR策略的线程在一个条件变量上等待或等待加锁同一个互斥量时,它们将以优先级顺序被唤醒。即,如果一个低优先级的SCHED_FIFO线程和一个高优先级的SCHED_FIFO线程都在等待锁相同的互斥量,则当互斥量被解锁时,高优先级线程将总是被首先解除阻塞。

(4)线程的调度参数

#include<pthread.h>int pthread_attr_getschedparam(const pthread_attr_t*attr,struct sched_param *param);//获取线程的调度参数int pthread_attr_setschedparam(pthread_attr_t *attr,conststruct sched_param *param);//设置线程的调度参数

若成功返回0,若失败返回-1。
attr: 线程属性变量指针。
param:sched_param结构。结构sched_param在文件/usr/include/bits/sched.h中定义如下:
struct sched_param
{
intsched_priority;
};
结构sched_param的子成员sched_priority控制一个优先权值,大的优先权值对应高的优先权。系统支持的最大和最小优先权值可以用sched_get_priority_max函数和sched_get_priority_min函数分别得到。

(3) 等待其他线程退出函数

#include <pthread.h>int pthread_join(pthread_t thread, void **retval);

返回值 : 0代表成功。 失败,返回的则是错误号。
thread:线程ID。
retval: 用户定义的指针,用来存储被等待线程的返回值。
以阻塞的方式等待thread指定的线程结束。当函数返回时,被等待线程的资源被收回。如果线程已经结束,那么该函数会立即返回。并且thread指定的线程必须是joinable的。

三、实例分析
根据上述线程相关函数,有一个如下实例:

#include <string.h>#include <semaphore.h>#define MODULE_NAME_MAX_LEN    32       /* 定义模块名字最大长度 *//*初始化优先级枚举*/typedef enum{    INIT_RIGHT_START,    INIT_TOP_RIGHT=1,    INIT_HIGH_RIGHT,    INIT_NORMAL_RIGHT,    INIT_LOW_RIGHT,    INIT_RIGHT_END,}INIT_RIGHTS;typedef void* (* PF_TASK_MAIN )(void* arg);typedef unsigned long (* PF_INIT_FUNC )(unsigned long thread_id); typedef struct  ThreadCtl{    unsigned long thread_id; /* 线程ID   ,固定分配*/    char thread_name[MODULE_NAME_MAX_LEN];          /* 模块名   */    PF_INIT_FUNC init_func; /* 各个模块的初始化入口函数 */    unsigned long task_id;   /* 模块任务ID,创建线程时,返回此值   */         unsigned long init_pri;/*模块的初始化优先级*/    unsigned long task_pri; /* 各个模块的任务优先级 */    int policy; /* 模块对应线程的调试策略*/    PF_TASK_MAIN task_func;  /* 各个模块的任务入口函数 */    unsigned long task_para; /* 各个模块的任务入口参数 */}thread_ctrl_t;typedef enum{    /*0模块ID预留*/    THREAD_ZERO_ID,     /*特殊模块号,主线程模块ID*/    THREAD_MAIN_ID,    /*在此处罗列模块枚举*/    THREAD_ONE_ID,    THREAD_TWO_ID,    /*模块结束ID*/     THREAD_END_ID,}MODULE_IDS;void init_main_thread_info(void);void init_thread_list(void);void init_module_manager(void);int mod_if_register_thread(int thread_id,int init_right,int task_right,char * thread_name,                            PF_INIT_FUNC init_func,PF_TASK_MAIN func_entry, int policy);
#include <stdio.h>#include <iostream>#include <sys/types.h>#include <sys/ipc.h>#include <pthread.h>#include "module.h"using namespace std;/*  在这里定义所有的应用模块,注意这里的数组需要和模块ID对应起来,方便管理*/thread_ctrl_t  thread_info[THREAD_END_ID+1];/******将主线程的信息与其他线程信息一同管**理在此函数中完成主线程信息的特殊初始化流程**************************************************/void init_main_thread_info(void){    thread_info[THREAD_MAIN_ID].thread_id = THREAD_MAIN_ID;    strcpy(thread_info[THREAD_MAIN_ID].thread_name, "Main Thread");    thread_info[THREAD_MAIN_ID].init_func = NULL;    thread_info[THREAD_MAIN_ID].task_id = pthread_self();//获取自身线程的ID值    thread_info[THREAD_MAIN_ID].init_pri= INIT_TOP_RIGHT;    thread_info[THREAD_MAIN_ID].task_pri= 0;    thread_info[THREAD_MAIN_ID].task_func= NULL;    thread_info[THREAD_MAIN_ID].task_para= 0;}/***********显式初始化模块注册数组***************/void init_thread_list(void){    int thread_id;        for(thread_id = THREAD_ZERO_ID;thread_id < THREAD_END_ID+1;thread_id++)    {        thread_info[thread_id].thread_id= 0;        strcpy(thread_info[thread_id].thread_name, "null");        thread_info[thread_id].init_func= NULL;        thread_info[thread_id].task_id= 0;        thread_info[thread_id].init_pri= 0;        thread_info[thread_id].task_pri= 0;        thread_info[thread_id].task_func= NULL;        thread_info[thread_id].task_para= 0;    }}/**********获取对应模块的线程优先级**************/int mod_if_get_thread_priority(int thread_id){    int result;    result = thread_info[thread_id].task_pri;    return result;}/******************创建线程*********************/int task_create(unsigned int thread_id, unsigned long* p_tidp, int policy, PF_TASK_MAIN func_entry,void * args){    if (p_tidp == NULL)    {        return -1;    }    int result;    pthread_attr_t pattr;    struct sched_param param;    pthread_attr_init(&pattr);    param.sched_priority = mod_if_get_thread_priority(thread_id);       pthread_attr_setschedpolicy(&pattr,policy);    pthread_attr_setschedparam(&pattr,&param);    pthread_attr_setinheritsched(&pattr,PTHREAD_EXPLICIT_SCHED);    result = pthread_create(p_tidp,                            &pattr,                            func_entry,                            args);    pthread_attr_destroy(&pattr);    return result;}void startup_module(int thread_id){task_create(thread_id, &thread_info[thread_id].task_id, thread_info[thread_id].policy, thread_info[thread_id].task_func, NULL);}/*按照模块注册时传入的初始化优先级进行模块初始化并创建线程*/void startup_module_flowline(void){    int init_right = 0;    int moduleid = 0;    int init_result = 0;    for(init_right = INIT_TOP_RIGHT;init_right <  INIT_RIGHT_END;init_right++)    {        for(moduleid = THREAD_ZERO_ID+1;moduleid < THREAD_END_ID;moduleid++)        {            if((thread_info[moduleid].init_pri== init_right)&&(moduleid != THREAD_MAIN_ID))            {                if(thread_info[moduleid].init_func != NULL)                {                    init_result = thread_info[moduleid].init_func(moduleid);                }                startup_module(moduleid);            }            else            {                continue;            }        }    }}/****按照与启动时相反的顺序以阻塞主线程的方式等待线程结束*****/void block_module_queue(void){    int init_right = 0;    int moduleid = 0;    for(init_right = INIT_RIGHT_END - 1; init_right > INIT_RIGHT_START; init_right--)    {        for(moduleid = THREAD_END_ID - 1; moduleid > THREAD_ZERO_ID; moduleid--)        {            if((thread_info[moduleid].init_pri== init_right)&&(moduleid != THREAD_MAIN_ID))            {                if(strcmp(thread_info[moduleid].thread_name,"null"))                {                pthread_join(thread_info[moduleid].task_id,NULL);                }            }        }    }}/***************模块管理的入口函数**********************/void init_module_manager(void){    startup_module_flowline();    block_module_queue();}/******************************************************************   *  函数名:          mod_if_register_module   *  功能:           模块注册函数       *  输入参数: thread_id:模块ID号                    init_right:初始化优先级(模块启动顺序)                    task_right:任务优先级(线程优先级 1~99)                    thread_name:模块名                    init_func:模块初始化入口(申请消息队列和信号量,初始化全局变量)                    task_func:模块主函数入口                    policy: 线程的调试策略(SCHED_FIFO, SCHED_OTHER, SCHED_RR)******/int mod_if_register_thread(int thread_id,int init_right,int task_right,char * thread_name,PF_INIT_FUNC init_func,PF_TASK_MAIN func_entry, int policy){if(thread_id >= THREAD_END_ID)    {        printf("module error!!!\n");        return -1;    }    if((task_right < 1) ||(task_right > 99))    {                printf("The value of task priority should between 1 and 99!\n");        while(1);    }if((thread_info[thread_id].thread_id == 0)&&(thread_info[thread_id].init_pri ==0)        &&(thread_info[thread_id].task_pri == 0)&&(strcmp(thread_info[thread_id].thread_name,"null") == 0)        &&(thread_info[thread_id].init_func == NULL)&&(thread_info[thread_id].task_func == NULL))    {        thread_info[thread_id].thread_id= thread_id;        thread_info[thread_id].init_pri= init_right;        thread_info[thread_id].task_pri= task_right;        strcpy(thread_info[thread_id].thread_name,thread_name);        thread_info[thread_id].init_func= init_func;        thread_info[thread_id].task_func= func_entry;        thread_info[thread_id].policy = policy;    }    else    {        printf("Registered module ID!\n");        while(1);    }}
#include <stdio.h>#include <string.h>#include <iostream>#include <signal.h>#include "module.h"/*******************线程1执行的入口函数******/void *thread_one_main(void* arg) {    while(true)    {           sleep(3);               printf("MODULE ONE main func++++++++++++\n");    }}/*******************线程2执行的入口函数******/void *thread_two_main(void* arg) {    while(true)    {        printf("MODULE TWO main func------------\n");        sleep(3);    }}/*******************主函数main******************/int main(void){    init_main_thread_info();    init_thread_list();    mod_if_register_thread(THREAD_ONE_ID,                            INIT_TOP_RIGHT,                            1,                            const_cast<char *>("test thread1~~~"),                            NULL,                            thread_one_main,                            SCHED_OTHER);    mod_if_register_thread(THREAD_TWO_ID,                            INIT_TOP_RIGHT,                            3,                            const_cast<char *>("test thread2~~~"),                            NULL,                            thread_two_main,                            SCHED_OTHER);    init_module_manager();}
GG = g++CPPFLAGES = -std=c++0x -pthreadCPPRCS := $(wildcard *.cpp)OBJS := $(CPPRCS:%.cpp=%.o)main: main.o module.o    $(GG) $(CPPFLAGES) -o $@ $^    @echo $@%.o: %.cpp    $(GG) $(CPPFLAGES) -c $< -o $@    @echo $@.PHONY: cleanclean:    rm -rf *.o main
0 0
原创粉丝点击