一个进程可以包含多个线程,多个线程共享同一份全局内存区域,包括初始化数据段(initialized data)、未初始化数据段(uninitialized data)以及堆内存段(heap segment).
对于某些应用而言,线程要优于进程:
1.进程间信息难以共享,必须使用进程间通信IPC方式,在进程间进行消息通信。
2.使用fork创建进程带价较高。
线程解决了上面两个问题:
1.线程之间能够方便、快速共享信息,需要使用线程同步技术(互斥锁 条件变量)
2.创建线程比创建进程快(实现线程是通过clone()系统调用)

/*************************************************************************\
*                  Copyright (C) Michael Kerrisk, 2018.                   *
*                                                                         *
* This program is free software. You may use, modify, and redistribute it *
* under the terms of the GNU General Public License as published by the   *
* Free Software Foundation, either version 3 or (at your option) any      *
* later version. This program is distributed without any warranty.  See   *
* the file COPYING.gpl-v3 for details.                                    *
\*************************************************************************/

/* Listing 29-1 */

/* simple_thread.c

   A simple POSIX threads example: create a thread, and then join with it.
*/
#include <pthread.h>
#include "tlpi_hdr.h"

static void *
threadFunc(void *arg)
{
    char *s = (char *) arg;

    printf("%s", s);

    return (void *) strlen(s);
}

int
main(int argc, char *argv[])
{
    pthread_t t1;
    void *res;
    int s;

    s = pthread_create(&t1, NULL, threadFunc, "Hello world\n");
    if (s != 0)
        errExitEN(s, "pthread_create");

    printf("Message from main()\n");
    s = pthread_join(t1, &res);
    if (s != 0)
        errExitEN(s, "pthread_join");

    printf("Thread returned %ld\n", (long) res);

    exit(EXIT_SUCCESS);
}

执行结果:

[root threads]#./simple_thread
Message from main()
Hello world
Thread returned 12
[root threads]#

上面输出汇总的Message from main()与Hello world可能会颠倒过来,依赖于系统对两个线程的具体调度顺序。

#include <pthread.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
void printids(const char *s)
{
    pid_t   pid;
    pthread_t   tid;
    /*getpid获取当前进程的ID*/
    pid = getpid();
    /*pthread_self获取自己的线程ID*/
    tid = pthread_self();
    printf("%s pid = %lu tid = %lu\n", s, (unsigned long)pid, (unsigned long)tid);
}

void* thr_fn(void *arg)
{
    printids("new  thread:");
    return((void*)0);
}
int main()
{
    int    err;
    pthread_t ntid;
    err = pthread_create(&ntid, NULL, thr_fn, NULL);
    if(err!=0)
    {
        printf("can't create thread\n");
        exit(1);
    }
    printids("main thread:");
    /*如果不设置休眠,有可能在新线程执行之前就退出*/
    sleep(4);
    printf("%m\n");
    exit(0);
}

printf("%m")用法如下,参考man手册:
m (Glibc extension.) Print output of strerror(errno). No argument is required.
等价于:
printf("%s",strerror(errno));

有关线程这部分内容一篇非常不错的文章POSIX Threads Programming

线程的分离

#include <pthread.h>
int pthread_detach(pthread_t thread)

默认情况下,线程是可连接的(joinable),也就是说,当线程退出时,其它线程可以通过调用pthread_join()获取其返回状态。有时,程序员并不关心线程的返回状态,只是希望系统在线程终止时能够自动清理并移除之。在这种情况下,可以调用pthread_detach()并向thread参数传入指定线程的标识符,该线程标记为处于分离(detached)状态。
一旦线程处于分离状态,就不能再使用pthread_join()来获取其状态,也无法重返可连接状态。

/*************************************************************************\
*                  Copyright (C) Michael Kerrisk, 2018.                   *
*                                                                         *
* This program is free software. You may use, modify, and redistribute it *
* under the terms of the GNU General Public License as published by the   *
* Free Software Foundation, either version 3 or (at your option) any      *
* later version. This program is distributed without any warranty.  See   *
* the file COPYING.gpl-v3 for details.                                    *
\*************************************************************************/

/* Listing 29-2 */

/* detached_attrib.c

   An example of the use of POSIX thread attributes (pthread_attr_t):
   creating a detached thread.
*/
#include <pthread.h>
#include "tlpi_hdr.h"

static void *
threadFunc(void *x)
{
    return x;
}

int
main(int argc, char *argv[])
{
    pthread_t thr;
    pthread_attr_t attr;
    int s;

    s = pthread_attr_init(&attr);       /* Assigns default values */
    if (s != 0)
        errExitEN(s, "pthread_attr_init");

    s = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    if (s != 0)
        errExitEN(s, "pthread_attr_setdetachstate");

    s = pthread_create(&thr, &attr, threadFunc, (void *) 1);
    if (s != 0)
        errExitEN(s, "pthread_create");

    s = pthread_attr_destroy(&attr);    /* No longer needed */
    if (s != 0)
        errExitEN(s, "pthread_attr_destroy");

    s = pthread_join(thr, NULL);
    if (s != 0)
        errExitEN(s, "pthread_join failed as expected");

    exit(EXIT_SUCCESS);
}

上面的例子演示了创建一个线程,该线程一创建即遭分离,而非之后再调用pthread_detach()。

总结

多线程编程时需要确保调用线程安全函数,或者以线程安全的方式调用函数。多进程应用则无需关注这些。
线程和进程间的关键区别在于,线程比进程更易于共享信息,这也是许多应用程序舍进程而取线程的原因。对于某些操作来说(线程创建比进程快),线程还可以提供更好的性能。
可以使用pthread_create()来创建线程。每个线程随后可调用pthread_exit()退出,如果有任一线程调用了exit(),那么所有的线程将立即终止。
如果没有将线程标记为分离状态,则该线程需要使用pthread_join连接,由该函数返回线程退出状态。