linux 线程相关函数

linux多线程pthread系列函数详解

  • 为什么要引入线程

线程技术早在60年代就被提出,但是在80年代才真正使用到操作系统中。传统UNIX也支持多线程概念,但在一个进程中只允许有一个线程,这样多线程就意味着多进程。现在多线程技术已经被很多操作系统支持,包含Windows/NT,当然也包含Linux。

我们知道新建立一个进程的代价是非常昂贵的,内核需要分配一个新的地址空间,建立众多的数据表来维护他的数据段/代码段等。但是在一个进程中的多个线程,使用相同的地址空间,共享大部分数据,新建立一个线程花费的时间要远远小于新建一个进程,而且,线程之间的切换速度也远远小于进程的切换速度。

另外一点是通信的快速,进程由于有独立的地址空间,进程的数据传递往往使用通信的方式。而线程共享同一个数据空间,多个线程之间只需要做好数据保护,就可以直接使用数据,避免拷贝。

线程优点总结以下几个方面:

1)提高程序响应速度。比如按键响应这种耗时的操作可以在一个新建立的线程中去做,这样就不会影响其他的程序执行。

2)改善程序结构,复杂的逻辑可以按照业务拆分出多个线程处理,程序会利于修改与整理。

3)更好的应用于SMP系统,一个进程的多个线程可以分配到不同CPU上面运行。

相关API

pthread_create()

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

返回值
成功后,pthread_create()返回0;出现错误时,它返回一个错误号,以及的内容线程未定义。
错误码:
EAGAIN 资源不足,无法创建另一个线程,或者系统对数量施加了限制遇到个线程。后一种情况可能以两种方式发生:RLIMIT_NPROC软资源limit(通过setrlimit(2)设置),它限制了真实用户ID的进程数量达到;或者内核对线程数量的系统范围限制,/proc/sys/kernel/threads-max。
EINVAL 属性中的设置无效。
EPERM 没有设置属性中指定的调度策略和参数的权限。

pthread_exit()

void pthread_exit(void *retval);

pthread_join()

功能:阻塞当前线程,直到另一个线程执行结束

int pthread_join(pthread_t thread, void **retval);

返回值
成功后,pthread_join()返回 0
EDEADLK 检测到死锁(例如,两个线程试图相互连接);或线程指定调用线程。
EINVAL 线程不是可连接的线程。
EINVAL 另一个线程已在等待加入此线程。
ESRCH 找不到ID为的线程。

pthread_attr_init()

int pthread_attr_init(pthread_attr_t *attr);
int pthread_attr_destroy(pthread_attr_t *attr);

属性有很多,直接看下面的例子:

下面代码的执行效果:

Thread attributes:
Detach state = PTHREAD_CREATE_JOINABLE
Scope = PTHREAD_SCOPE_SYSTEM
Inherit scheduler = PTHREAD_INHERIT_SCHED
Scheduling policy = SCHED_OTHER
Scheduling priority = 0
Guard size = 4096 bytes
Stack address = 0x7f95091ea000
Stack size = 0x801000 bytes

/*gcc main.c -lpthread -o m*/
#define _GNU_SOURCE     /* To get pthread_getattr_np() declaration */
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>

#define handle_error_en(en, msg) \
        do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)

static void display_pthread_attr(pthread_attr_t *attr, char *prefix)
{
    int s, i;
    size_t v;
    void *stkaddr;
    struct sched_param sp;

    s = pthread_attr_getdetachstate(attr, &i);
    if (s != 0)
        handle_error_en(s, "pthread_attr_getdetachstate");
    printf("%sDetach state        = %s\n", prefix,
            (i == PTHREAD_CREATE_DETACHED) ? "PTHREAD_CREATE_DETACHED" :
            (i == PTHREAD_CREATE_JOINABLE) ? "PTHREAD_CREATE_JOINABLE" :
            "???");

    s = pthread_attr_getscope(attr, &i);
    if (s != 0)
        handle_error_en(s, "pthread_attr_getscope");
    printf("%sScope               = %s\n", prefix,
            (i == PTHREAD_SCOPE_SYSTEM)  ? "PTHREAD_SCOPE_SYSTEM" :
            (i == PTHREAD_SCOPE_PROCESS) ? "PTHREAD_SCOPE_PROCESS" :
            "???");

    s = pthread_attr_getinheritsched(attr, &i);
    if (s != 0)
        handle_error_en(s, "pthread_attr_getinheritsched");
    printf("%sInherit scheduler   = %s\n", prefix,
            (i == PTHREAD_INHERIT_SCHED)  ? "PTHREAD_INHERIT_SCHED" :
            (i == PTHREAD_EXPLICIT_SCHED) ? "PTHREAD_EXPLICIT_SCHED" :
            "???");

    s = pthread_attr_getschedpolicy(attr, &i);
    if (s != 0)
        handle_error_en(s, "pthread_attr_getschedpolicy");
    printf("%sScheduling policy   = %s\n", prefix,
            (i == SCHED_OTHER) ? "SCHED_OTHER" :
            (i == SCHED_FIFO)  ? "SCHED_FIFO" :
            (i == SCHED_RR)    ? "SCHED_RR" :
            "???");

    s = pthread_attr_getschedparam(attr, &sp);
    if (s != 0)
        handle_error_en(s, "pthread_attr_getschedparam");
    printf("%sScheduling priority = %d\n", prefix, sp.sched_priority);

    s = pthread_attr_getguardsize(attr, &v);
    if (s != 0)
        handle_error_en(s, "pthread_attr_getguardsize");
    printf("%sGuard size          = %d bytes\n", prefix, v);

    s = pthread_attr_getstack(attr, &stkaddr, &v);
    if (s != 0)
        handle_error_en(s, "pthread_attr_getstack");
    printf("%sStack address       = %p\n", prefix, stkaddr);
    printf("%sStack size          = 0x%x bytes\n", prefix, v);
}

static void * thread_start(void *arg)
{
    int s;
    pthread_attr_t gattr;

    /* pthread_getattr_np() is a non-standard GNU extension that
       retrieves the attributes of the thread specified in its
       first argument */

    s = pthread_getattr_np(pthread_self(), &gattr);
    if (s != 0)
        handle_error_en(s, "pthread_getattr_np");

    printf("Thread attributes:\n");
    display_pthread_attr(&gattr, "\t");

    exit(EXIT_SUCCESS);         /* Terminate all threads */
}

int main(int argc, char *argv[])
{
    pthread_t thr;
    pthread_attr_t attr;
    pthread_attr_t *attrp;      /* NULL or &attr */
    int s;

    attrp = NULL;

    /* If a command-line argument was supplied, use it to set the
       stack-size attribute and set a few other thread attributes,
       and set attrp pointing to thread attributes object */

    if (argc > 1) {
        int stack_size;
        void *sp;

        attrp = &attr;
        s = pthread_attr_init(&attr);
        if (s != 0)
            handle_error_en(s, "pthread_attr_init");

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

        s = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
        if (s != 0)
            handle_error_en(s, "pthread_attr_setinheritsched");

        stack_size = strtoul(argv[1], NULL, 0);

        s = posix_memalign(&sp, sysconf(_SC_PAGESIZE), stack_size);
        if (s != 0)
            handle_error_en(s, "posix_memalign");

        printf("posix_memalign() allocated at %p\n", sp);

        s = pthread_attr_setstack(&attr, sp, stack_size);
        if (s != 0)
            handle_error_en(s, "pthread_attr_setstack");
    }

    s = pthread_create(&thr, attrp, &thread_start, NULL);
    if (s != 0)
        handle_error_en(s, "pthread_create");

    if (attrp != NULL) {
        s = pthread_attr_destroy(attrp);
        if (s != 0)
            handle_error_en(s, "pthread_attr_destroy");
    }

    pause();    /* Terminates when other thread calls exit() */
}

pthread_kill()

给指定线程发送信号

int pthread_kill(pthread_t thread, int sig);

返回值
成功后,pthread_kill()返回0;出现错误时,它返回一个错误编号,并且不发送任何信号。
错误:
EINVAL — 指定了无效信号。
ESRCH — 找不到ID为的线程。

线程同步

pthread_mutex_lock():互斥加锁
pthread_mutex_trylock()
pthread_mutex_unlock():互斥锁解锁
pthread_cond_init():初始化条件变量
pthread_cond_signal():发送信号唤醒进程
pthread_cond_wait():等待条件变量的特殊事件发生

pthread_mutex_t  mutex = PTHREAD_MUTEX_INITIALIZER;

/**
 * @ 动态初始化一个mutex锁
 * @ mutex: 指定要初始化的mutex锁的地址        mutexattr: NULL 默认值
 * @ 总是成功返回0
 */
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr);

/**
 * @ 销毁mutex锁,释放锁hold的资源
 * @ mutex: 指定要销毁的锁的地址
 * @ 成功返回0,失败返回非0的错误码
 */
int pthread_mutex_destroy(pthread_mutex_t *mutex);

/**
 * @ 加锁 如果锁被其他线程占用,阻塞等待其他线程解锁,如果锁处于解锁状态,加锁,立即返回
 * @ mutex: 指定要加锁的锁的地址
 * @ 成功返回0,失败返回非0的错误码
 */
int pthread_mutex_lock(pthread_mutex_t *mutex);

/**
 * @ 尝试加锁 如果锁处于解锁状态,加锁,立即返回,如果锁被其他线程占用,立即返回错误EBUSY
 * @ mutex: 指定要加锁的锁地址
 * @ 成功返回0,失败返回非0的错误码
 */
int pthread_mutex_trylock(pthread_mutex_t *mutex);


/**
 * @ 解锁
 * @ mutex: 指定锁的地址
 * @ 成功返回0,失败返回非0的错误码
 */
int pthread_mutex_unlock(pthread_mutex_t *mutex);
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr);
int pthread_cond_destroy(pthread_cond_t *cond); 
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)  
int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime) 
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);
  • 9
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值