linux c 线程的创建与结束 (传参和返回值)

原创 2014年08月15日 16:35:41

1. 线程的创建

1.1 线程创建函数

intpthread_create(
pthread_t*tidp,//线程的标识符指针
const pthread_attr_t*attr,//线程属性【重要】
(void*)(*start_rtn)(void*),//线程函数其实地址
void*arg//运行函数的参数
);

所属头文件:<pthread.h>

由于不属于默认库,所以编译的时候需加-lpthread

如果你是使用的code::blocks,(我就是),需在 project -> build option -> linker setting中add添加   pthread (注:没有无需 l)

1.2  pthread_attr 的相关说明

pthread_attr属性描述了线程的运行状态:

__detachstate: 表示新线程是否与进程中其他线程脱离同步,如果置位则新线程不能用pthread_join()来同步,且在退出时自行释放所占用的资源。缺省为PTHREAD_CREATE_JOINABLE状态。这个属性也可以在线程创建并运行以后用pthread_detach()来设置,而一旦设置为PTHREAD_CREATE_DETACH状态(不论是创建时设置还是运行时设置)则不能再恢复到PTHREAD_CREATE_JOINABLE状态。

__schedpolicy,表示新线程的调度策略,主要包括SCHED_OTHER(正常、非实时)、SCHED_RR(实时、轮转法)和SCHED_FIFO(实时、先入先出)三种,缺省为SCHED_OTHER,后两种调度策略仅对超级用户有效。在线程函数中可以用过pthread_setschedparam()来改变。

__schedparam,一个struct sched_param结构,目前仅有一个sched_priority整型变量表示线程的运行优先级。这个参数仅当调度策略为实时(即SCHED_RR或SCHED_FIFO)时才有效,并可以在运行时通过pthread_setschedparam()函数来改变,缺省为0。

__inheritsched,有两种值可供选择:PTHREAD_EXPLICIT_SCHEDPTHREAD_INHERIT_SCHED,前者表示新线程使用显式指定调度策略和调度参数(即attr中的值),而后者表示继承调用者线程的值。缺省为PTHREAD_EXPLICIT_SCHED

__scope,表示线程间竞争CPU的范围,也就是说线程优先级的有效范围。POSIX的标准中定义了两个值:PTHREAD_SCOPE_SYSTEMPTHREAD_SCOPE_PROCESS,前者表示与系统中所有线程一起竞争CPU时间,后者表示仅与同进程中的线程竞争CPU。目前LinuxThreads仅实现了PTHREAD_SCOPE_SYSTEM一值。


用得比较多的是__detachstate,因为它决定了线程的结束方式,在之后的实例中会有更直观的体现。

2. 线程的结束

线程结束的方式主要有两种,一个是线程函数内部结束,一个是从线程外部,也就是在其他线程或主进程中通过线程标识符指针结束该线程。

内部结束:调用void pthread_exit(void* retVal); 和 return的方式是同等的效果。

外部结束:调用int pthread_cancel(pthread_t tid),该函数只是向线程发送取消信号,成功返回0,发送失败则返回非零值。至于线程是否结束,何时结束则取决于线程的一些属性设置。

关于结束还有个非常重要的一点,线程资源的回收。回收的方式取决于线程是何种分离状态,也就是之前提到的__detachstate。

线程的分离状态有两种,joinable和detached。

简单的来说,detached状态的线程可以自我管理进行回收,而joinable的线程需要在线程结束后再调用pthread_join 来回收线程资源。若线程为结束,则pthread_join会阻塞等待。


3. 几个例子来说明一些问题


3.1 joinable状态下线程的结束和结束后返回参数

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

extern void* threadFun(void* arg);

int main()
{
    char pNameA[20] = "I'am thread A";
    pthread_t pid;
    pthread_create(&pid, NULL, threadFun, pNameA);
    char* retStr = 0;
    pthread_join(pid, (void**)&retStr);
    printf("Main process:%s.\r\n", retStr);
    delete[] retStr;
    return 0;
}

void* threadFun(void* arg)
{
    char* pName = (char*)arg;
    int count = 0;
    while(count < 5)
    {
        printf("%s, count:%d\r\n", pName, count);
        sleep(1);
        count++;
    }
    char* retVal = new char[32];
    sprintf(retVal, "%s, final count is:%d.", pName, count);
    return ((void*)retVal);
}

这段代码所做的事情:
1. 向线程传递一个字符串参数“I‘am thread A”,
2. 然后在线程中答应这个参数并开始计数,计数到五时返回计数结果
3. 主线程中pthread_join阻塞等待回收线程并获取返回结果并打印

为了让返回值传得出来所以new了一个字符串数组。
这是一个比较自然的结束过程,线程函数运行完成之后,主线程进行资源回收。
但有时候我们线程的结束与否是由线程外部决定的,所以看下面的例子

3.2 外部结束线程和设置取消点
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>


extern void* threadFun(void* arg);


int main()
{
    pthread_t pid;
    pthread_attr_t attr;
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);


    pthread_create(&pid, &attr, threadFun, NULL);
    printf("5s later, the thread will be canceled.\r\n");
    sleep(5);
    int err = 0;
    printf("sending cancel info.\r\n");
    if( (err = pthread_cancel(pid)) != 0)
    {
        printf("error - %s\r\n", strerror(err));
        return 0;
    }
    
    if((err = pthread_join(pid, NULL)) != 0)
    {
        printf("error - %s\r\n", strerror(err));
        return 0;
    }
    printf("thread has been canceled.\r\n");
    return 0;
}


void* threadFun(void* arg)
{
    //pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
    //pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
    pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
    printf("A thread is running.\r\n");
    while(1)
    {
        int a = 2;
        a++;
        //pthread_testcancel();
    }
    return ((void*)arg);
}

这段代码所做的事情:

1. 创建一个线程,5s后cancel掉它。

2. 由于线程默认时joinable状态的,thread_cancel后调用thread_join来进行回收。

可以注意到,我们在线程函数的开始设置了cancelstate,而实际上它的默认值就是PTHREAD_CANCEL_ENABLE。若设置为UNABLE,则该线程将无法从外部结束

至于canceltype,设置为PTHREAD_CANCEL_DEFERRED时是指接收到结束信号以后,运行至取消点再结束。PTHREAD_CANCEL_ASYNCHRONOUS则是立即结束。默认为PTHREAD_CANCEL_DEFERRED。

如上代码中,在while的循环中时没有取消点的。所以这里,若canceltype为DEFERRED,则需要设置一个取消点。若没有取消点,即使收到取消信号线程也不会停止。(根据POSIX语义,有些方法中带有取消点,如printf等,但是read和write操作在linux C中却没有实现取消点,所以在写的时候需要在其前后设置取消点。)


3.3 detached狀態下线程的結束,以及未回收線程的內存泄漏問題

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

extern void* threadFun(void* arg);

int main()
{
    pthread_t pid;
    pthread_attr_t attr;
    pthread_attr_init(&attr);
    //pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

    int count = 1;
    while(1)
    {
        pthread_create(&pid, &attr, threadFun, NULL);
        printf("%d threads has been created.\r\b", count++);
        fflush(stdout);
        usleep(800);
    }
    return 0;
}

void* threadFun(void* arg)
{
    return ((void*)arg);
}

這段代碼所做的事情: 不停的創建線程

上段代碼會造成內存泄漏,原因在於线程運行並結束後,未进行pthread_join的回收,如下图


内存使用率达到了6.8% 这里显然是发生了泄漏.有意思的是当泄漏到这么多时,内存使用率就不再上涨了.

如果觉得每次回收线程都要使用pthread_join是件很麻烦的事情,可以将线程设置为detached状态,这样就不会造成内存泄漏了.(即取消那行注释即可,当然也可以在线程内部进行设置)

相关文章推荐

pthread_create()函数用法

linux下用C开发多线程程序,Linux系统下的多线程遵循POSIX线程接口,称为pthread。 #include int pthread_create(pthrea...

pthread_create() 返回 11

通过反复的 pthread_create() --->   pthread_exit (0)   一段时间后,会导致pthread_create() 失败,返回11 google后,发现,单纯地调用...
  • hailmy
  • hailmy
  • 2015年02月27日 12:26
  • 1852

pthread_create()

pthread_create函数     原型:int  pthread_create((pthread_t  *thread,  pthread_attr_t  *attr,  void  *(*...

pthread_create 的返回值

转载自:http://blog.csdn.net/charlie_2010/article/details/6052898 上午做个测试程序,模拟多客户端测试服务器压力,开始时有的客户端总是显示断...

pthread_join来接收线程的返回参数

pthread_join用来等待一个线程的结束。函数原型为:   extern int pthread_join (pthread_t__th, void **__thread_return); ...

C/C++中退出线程的四种解决方法

退出线程可以有四种方法: 1.线程函数的return返回(最好这样): 其中用线程函数的return返回, 而终止线程是最安全的, 在线程函数return返回后, 会清理函数内申请的类对象, 即调...

VC退出线程的方法

标题很简单,但是要讨论的地方不少; 多线程管理,在程序开发中非常重要,虽然...

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载

如何终止线程的运行(C/C++)

如何终止线程的运行(C/C++) 想要终止线程的运行,可以使用以下方法:  1、线程函数返回(最好使用该方法)。  2、通过调用ExitThread函数,线程将自行撤消(最好不使用该方法)。  ...

pthread_create返回11解决方法

一直以为,程序创建线程,线程运行结束会自动清空资源 最近在一个项目中用到了线程,除去业务逻辑,我把他简化出来是下面这样//pthread.c #include #include static i...
  • cry1994
  • cry1994
  • 2016年09月24日 11:41
  • 2202
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:linux c 线程的创建与结束 (传参和返回值)
举报原因:
原因补充:

(最多只允许输入30个字)