美文网首页程序员
在Linux下创建线程(c语言)

在Linux下创建线程(c语言)

作者: Yojiaku | 来源:发表于2017-10-28 21:41 被阅读0次

    在Linux下创建线程(使用C语言)

    原文链接

    先看看线程是什么

    所有敲过代码的都或多或少写过一些程序programs. 比如: 显示"Hello World!", 判断一个数是否为素数prime number等等. 这些被称为"序列程序(sequential programs)", 它们每一个都拥有开头,执行顺序和结尾, 换句话说, 它们每一个都知道自己何时开始执行, 又何时结束.
    线程与这些序列程序的含义差不多. 一个线程(a single thread)也拥有一个开头, 顺序和结尾. 然而, 一个线程它本身并非一个程序(因为一个线程无法自我执行, 即它依赖于程序, 在程序中执行), 下图显示出一个程序和一个线程之间的关系:

    一个线程是一个程序中单个顺序的控制流程一个线程是一个程序中单个顺序的控制流程
    线程真正的作用在于多线程: 在同一时间同时运行多个线程, 即我们可以在一个程序中同时执行多个任务. 我们平时运行多个任务使用序列程序的话, 花的时间是所有任务执行时间的总和; 而多线程的话花费时间仅仅是任务中执行时间最长的那个. 如下图所示:

    线程标识符
    同进程用进程ID表示一样,一个线程也有一个线程ID来表明他的身份.但有趣的是,这两者之间有一点点不同:

    • A process ID is unique across the system where as a thread ID is unique only in context of a single process. (进程ID在整个系统中都是唯一的,而线程ID仅在单个进程的上下文中是唯一的,换句话说,其他进程中可能产生与这个进程中相同的线程ID)
    • A process ID is an integer value but the thread ID is not necessary an integer value. It could well be a structure. (进程ID是整型值,而线程ID不仅仅是整型值,还有可能是一个结构)
    • A process ID can be printed very easily while a thread ID is not easy to print.(进程ID能够很容易被打印出来,而线程ID并不那么轻易就能打印出来)

    线程ID可以用类型"pthread_t"表示.因为大多数情况下线程是一个结构,因此需要有一个能比较两线程的函数.

    #inlcude <pthread.h>
    int pthread_equal(pthread_t tid1, pthread_t tid2); // 判断两线程是否是同一个
    

    可以看到pthread_equal()函数接受两个线程参数,若他俩是同一个线程,就返回非0值,反之返回0.

    另一方面,我们有时候会出现需要知道这个线程的ID是多少的情况,因此,还需要下面这样一个函数

    #include <pthread.h>
    pthread_t pthread_self(void); // 返回自己的线程ID
    

    创建线程

    Normally when a program starts up and becomes a process, it starts with a default thread. So we can say that every process has at least one thread of control. A process can create extra threads using the following function:
    通常当一个程序建立并成为一个进程的时候,它将以默认线程开始.所以,我们可以说每个进程至少有一个控制线程,一个进程可以使用下面的函数创建额外的线程:

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

    参数解释:

    • 第一个参数是"pthread_t"类型的地址(address):一旦此函数调用成功,这个参数将会返回新创建的线程ID.
    • 第二个参数是线程属性,这些属性优先级将高于默认的线程属性.
    • 第三个参数是函数指针(a function pointer):每个线程从一个函数开始,并将此函数地址作为"第三个参数"传递到这里,以便内核(kernel)知道从哪个函数启动线程.
    • 作为函数(第三个参数)有可能需要传递一些参数进去,所以第四个参数便是以void类型指针的形式传递这些参数. *为什么选择void类型呢? *因为一个函数或许会接受不止一个参数,那么这个指针便可以是一个指向可能包含这些参数的结构的指针.

    一个具体的线程例子

    我们将上面提及的三个函数组成一个例子,以便有一个更直观的认识:

    #include <stdio.h>
    #include <string.h>
    #include <pthread.h> // for thread
    #include <stdlib.h> 
    #include <unistd.h>
    
    pthread_t tid[2];  // 创建两个线程
    
    void *doSomeThing(void *arg)
    {
        unsigned long i = 0;
        pthread_t id = pthread_self();
    
        if(pthread_equal(id, tid[0]))
        {
            printf("\n First thread processing\n"); // 第一个线程正在执行
        }
        else
        {
            printf("\n Second thread processing\n");
        }
        
        for(i=0; i<(0xFFFFFFFF); i++);
    
        return NULL;
    }
    
    int main(void)
    {
        int i = 0;
        int err;
    
        while(i < 2)
        {
            err = pthread_create(&(tid[i]), NULL, &doSomeThing, NULL);
            if(err != 0) printf("\n can't create thread:[%s]", strerror(err));
            else printf("\n Thread created successfully\n");
      
            i++;
        }
        sleep(5);
        return 0;
    }
    

    其中有两点还不是很合理的地方:

    1. doSomeThing()函数中最后的"return NULL";
    2. main函数中的"sleep()".

    对上述代码的解释:

    1. 使用了 pthread_create() 函数创建两个线程;
    2. 两个线程的启动函数都是 doSomeThing();
    3. doSomeThing() 函数中,线程使用 pthread_self()pthread_equal() 来确认正在执行的是线程1还是线程2;
    4. doSomeThing() 函数中的for循环只是为了浪费一点时间.

    现在,让我们看看执行结果:

    $ ./threadExample1
    
     Thread created successfully
    
     Thread created successfully
    
     First thread processing
    
     Second thread processing
    
    执行结果执行结果

    注意:执行线程的顺序总是不固定的,这取决于操作系统的调度算法

    相关文章

      网友评论

        本文标题:在Linux下创建线程(c语言)

        本文链接:https://www.haomeiwen.com/subject/pxsdpxtx.html