UNIX编程(12)-线程控制


 

1.线程限制

某些系统有线程的限制,可以通过sysconf函数来查询

2.线程属性

如想修改线程的属性,则可以在pthread_create调用时,传递pthread_attr_t类型指针参数

 

 

 

#include <pthread.h>

 

int pthread_attr_init(pthread_attr_t *attr);

 

int pthread_attr_destroy(pthread_attr_t   *attr);

 

 

Both return: 0 if OK, error number on failure


1)设置线程的分离状态

 

#include <pthread.h>

 

int pthread_attr_getdetachstate(const

 pthread_attr_t *restrict attr,

                                int *detachstate);

 

int pthread_attr_setdetachstate(pthread_attr_t

 *attr, int detachstate);

 

 

Both return: 0 if OK, error number on failure


例:以分离的状态创建线程

#include "apue.h"

#include <pthread.h>

 

int

makethread(void *(*fn)(void *), void *arg)

{

    int             err;

    pthread_t       tid;

    pthread_attr_t  attr;

 

    err = pthread_attr_init(&attr);

    if (err != 0)

        return(err);

    err = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

    if (err == 0)

        err = pthread_create(&tid, &attr, fn, arg);

    pthread_attr_destroy(&attr);

    return(err);

}


2)线程栈的操作接口

 

#include <pthread.h>

 

int pthread_attr_getstack(const pthread_attr_t

 *restrict attr,

                          void **restrict stackaddr,

                          size_t *restrict stacksize);

 

int pthread_attr_setstack(const pthread_attr_t *attr,

                          void *stackaddr, size_t

 *stacksize);

 

 

Both return: 0 if OK, error number on failure

 

 

#include <pthread.h>

 

int pthread_attr_getstacksize(const pthread_attr_t

 *restrict attr,

                              size_t *restrict

stacksize);

 

int pthread_attr_setstacksize(pthread_attr_t *attr

, size_t stacksize);

 

 

Both return: 0 if OK, error number on failure

3)guardsize,线程栈末尾之后用以避免栈溢出的扩展内存区

 

#include <pthread.h>

 

int pthread_attr_getguardsize(const pthread_attr_t

 *restrict attr,

                              size_t *restrict

guardsize);

 

int pthread_attr_setguardsize(pthread_attr_t *attr

, size_t guardsize);

 

 

Both return: 0 if OK, error number on failure


4)并发度

 

 

#include <pthread.h>

 

int pthread_getconcurrency(void);

 

 

Returns: current concurrency level

 

int pthread_setconcurrency(int level);

 

 

Returns: 0 if OK, error number on failure


3.同步属性

1)互斥量属性

 

#include <pthread.h>

 

int pthread_mutexattr_init(pthread_mutexattr_t *attr);

 

int pthread_mutexattr_destroy(pthread_mutexattr_t

 *attr);

 

 

Both return: 0 if OK, error number on failure


主要注意进程共享属性和类型属性

 

#include <pthread.h>

 

int pthread_mutexattr_getpshared(const

 pthread_mutexattr_t *

                                 restrict attr,

                                 int *restrict

pshared);

 

int pthread_mutexattr_setpshared

(pthread_mutexattr_t *attr,

                                 int pshared);

 

 

Both return: 0 if OK, error number on failure

 

#include <pthread.h>

 

int pthread_mutexattr_gettype(const

 pthread_mutexattr_t *

                              restrict attr, int

 *restrict type);

 

int pthread_mutexattr_settype(pthread_mutexattr_t

 *attr, int type);

 

 

Both return: 0 if OK, error number on failure


例:使用递归锁

#include "apue.h"

#include <pthread.h>

#include <time.h>

#include <sys/time.h>

 

extern int makethread(void *(*)(void *), void *);

 

struct to_info {

    void    (*to_fn)(void *);    /* function */

    void    *to_arg;             /* argument */

    struct timespec to_wait;     /* time to wait */

};

 

#define SECTONSEC  1000000000    /* seconds to nanoseconds */

#define USECTONSEC 1000          /* microseconds to nanoseconds */

 

void *

timeout_helper(void *arg)

{

    struct to_info *tip;

 

    tip = (struct to_info *)arg;

    nanosleep(&tip->to_wait, NULL);

    (*tip->to_fn)(tip->to_arg);

    return(0);

}

 

void

timeout(const struct timespec *when, void (*func)(void *), void *arg)

{

    struct timespec now;

    struct timeval  tv;

    struct to_info  *tip;

    int             err;

 

    gettimeofday(&tv, NULL);

    now.tv_sec = tv.tv_sec;

    now.tv_nsec = tv.tv_usec * USECTONSEC;

    if ((when->tv_sec > now.tv_sec) ||

      (when->tv_sec == now.tv_sec && when->tv_nsec > now.tv_nsec)) {

        tip = malloc(sizeof(struct to_info));

        if (tip != NULL) {

            tip->to_fn = func;

            tip->to_arg = arg;

            tip->to_wait.tv_sec = when->tv_sec - now.tv_sec;

            if (when->tv_nsec >= now.tv_nsec) {

                tip->to_wait.tv_nsec = when->tv_nsec - now.tv_nsec;

            } else {

                tip->to_wait.tv_sec--;

                tip->to_wait.tv_nsec = SECTONSEC - now.tv_nsec +

                  when->tv_nsec;

 

           }

           err = makethread(timeout_helper, (void *)tip);

           if (err == 0)

               return;

        }

    }

 

    /*

     * We get here if (a) when <= now, or (b) malloc fails, or

     * (c) we can't make a thread, so we just call the function now.

     */

    (*func)(arg);

}

 

pthread_mutexattr_t attr;

pthread_mutex_t mutex;

 

void

retry(void *arg)

{

    pthread_mutex_lock(&mutex);

    /* perform retry steps ... */

    pthread_mutex_unlock(&mutex);

}

 

int

main(void)

{

    int             err, condition, arg;

    struct timespec when;

 

    if ((err = pthread_mutexattr_init(&attr)) != 0)

        err_exit(err, "pthread_mutexattr_init failed");

    if ((err = pthread_mutexattr_settype(&attr,

      PTHREAD_MUTEX_RECURSIVE)) != 0)

        err_exit(err, "can't set recursive type");

    if ((err = pthread_mutex_init(&mutex, &attr)) != 0)

        err_exit(err, "can't create recursive mutex");

    /* ... */

    pthread_mutex_lock(&mutex);

    /* ... */

    if (condition) {

        /* calculate target time "when" */

        timeout(&when, retry, (void *)arg);

    }

    /* ... */

    pthread_mutex_unlock(&mutex);

    /* ... */

    exit(0);

}


2)读写锁属性

 

#include <pthread.h>

 

int pthread_rwlockattr_init(pthread_rwlockattr_t

 *attr);

 

int pthread_rwlockattr_destroy

(pthread_rwlockattr_t *attr);

 

 

Both return: 0 if OK, error number on failure

 

#include <pthread.h>

 

int pthread_rwlockattr_getpshared(const

 pthread_rwlockattr_t *

                                  restrict attr,

                                  int *restrict

pshared);

 

int pthread_rwlockattr_setpshared

(pthread_rwlockattr_t *attr,

                                  int pshared);

 

 

Both return: 0 if OK, error number on failure

3)条件变量属性

 

#include <pthread.h>

 

int pthread_condattr_init(pthread_condattr_t *attr);

 

int pthread_condattr_destroy(pthread_condattr_t

 *attr);

 

 

Both return: 0 if OK, error number on failure

 

#include <pthread.h>

 

int pthread_condattr_getpshared(const

 pthread_condattr_t *

                                restrict attr,

                                int *restrict

pshared);

 

int pthread_condattr_setpshared(pthread_condattr_t

 *attr,

                                int pshared);

 

 

Both return: 0 if OK, error number on failure


4.重入

一个函数在同一时刻可以被多个线程安全地调用,就称改函数是线程安全的。

5.线程私有数据

 

 

#include <pthread.h>

 

int pthread_key_create(pthread_key_t *keyp,

                       void (*destructor)(void *));

 

 

Returns: 0 if OK, error number on failure

 

 

#include <pthread.h>

 

int pthread_key_delete(pthread_key_t *key);

 

 

Returns: 0 if OK, error number on failure

 

#include <pthread.h>

 

pthread_once_t initflag = PTHREAD_ONCE_INIT;

 

int pthread_once(pthread_once_t *initflag, void

(*initfn)(void));

 

 

Returns: 0 if OK, error number on failure


键和线程私有数据的关联

 

 

#include <pthread.h>

 

void *pthread_getspecific(pthread_key_t key);

 

 

Returns: thread-specific data value or NULL if no value 
has been associated with the key

[View full width]

int pthread_setspecific(pthread_key_t key, const

void *value);

 

 

Returns: 0 if OK, error number on failure


6.取消选项

线程的可取消状态和可取消类型。这两个属性直接影响到pthread_cancel函数调用是呈现的行为

 

 

#include <pthread.h>

 

int pthread_setcancelstate(int state, int *oldstate);

 

 

Returns: 0 if OK, error number on failure

 

自己添加取消点

 

 

#include <pthread.h>

 

void pthread_testcancel(void);

 

 


修改取消类型

 

 

#include <pthread.h>

 

int pthread_setcanceltype(int type, int *oldtype);

 

 

Returns: 0 if OK, error number on failure


7. 线程和信号

 

#include <signal.h>

 

int pthread_sigmask(int how, const sigset_t

 *restrict set,

                    sigset_t *restrict oset);

 

 

Returns: 0 if OK, error number on failure

 

#include <signal.h>

 

int sigwait(const sigset_t *restrict set, int

 *restrict signop);

 

 

Returns: 0 if OK, error number on failure

 

 

#include <signal.h>

 

int pthread_kill(pthread_t thread, int signo);

 

 

Returns: 0 if OK, error number on failure


例:同步信号处理

#include "apue.h"

#include <pthread.h>

 

int         quitflag;   /* set nonzero by thread */

sigset_t    mask;

 

pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

pthread_cond_t wait = PTHREAD_COND_INITIALIZER;

 

void *

thr_fn(void *arg)

{

    int err, signo;

 

    for (;;) {

        err = sigwait(&mask, &signo);

        if (err != 0)

            err_exit(err, "sigwait failed");

        switch (signo) {

        case SIGINT:

            printf("\ninterrupt\n");

            break;

 

        case SIGQUIT:

            pthread_mutex_lock(&lock);

            quitflag = 1;

            pthread_mutex_unlock(&lock);

            pthread_cond_signal(&wait);

            return(0);

 

        default:

            printf("unexpected signal %d\n", signo);

            exit(1);

        }

    }

}

int

main(void)

{

    int         err;

    sigset_t    oldmask;

    pthread_t   tid;

 

    sigemptyset(&mask);

    sigaddset(&mask, SIGINT);

    sigaddset(&mask, SIGQUIT);

    if ((err = pthread_sigmask(SIG_BLOCK, &mask, &oldmask)) != 0)

        err_exit(err, "SIG_BLOCK error");

 

    err = pthread_create(&tid, NULL, thr_fn, 0);

    if (err != 0)

        err_exit(err, "can't create thread");

 

    pthread_mutex_lock(&lock);

    while (quitflag == 0)

        pthread_cond_wait(&wait, &lock);

    pthread_mutex_unlock(&lock);

 

    /* SIGQUIT has been caught and is now blocked; do whatever */

    quitflag = 0;

 

    /* reset signal mask which unblocks SIGQUIT */

    if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)

        err_sys("SIG_SETMASK error");

    exit(0);

}


 

8.线程和fork

 

在子进程内部只存在一个线程,它是由父进程中调用fork的线程的副本构成

如果父进程包含多个线程,子进程在fork返回后,如果接着不是马上调用exec的话,就需要清理锁状态


 

 

#include <pthread.h>

 

int pthread_atfork(void (*prepare)(void), void

(*parent)(void),

                   void (*child)(void));

 

 

Returns: 0 if OK, error number on failure


例:

#include "apue.h"

#include <pthread.h>

 

pthread_mutex_t lock1 = PTHREAD_MUTEX_INITIALIZER;

pthread_mutex_t lock2 = PTHREAD_MUTEX_INITIALIZER;

 

void

prepare(void)

{

    printf("preparing locks...\n");

    pthread_mutex_lock(&lock1);

    pthread_mutex_lock(&lock2);

}

void

parent(void)

{

    printf("parent unlocking locks...\n");

    pthread_mutex_unlock(&lock1);

    pthread_mutex_unlock(&lock2);

}

 

void

child(void)

{

    printf("child unlocking locks...\n");

    pthread_mutex_unlock(&lock1);

    pthread_mutex_unlock(&lock2);

}

 

void *

thr_fn(void *arg)

{

    printf("thread started...\n");

    pause();

    return(0);

}

 

int

main(void)

{

    int         err;

    pid_t       pid;

    pthread_t   tid;

 

#if defined(BSD) || defined(MACOS)

    printf("pthread_atfork is unsupported\n");

#else

    if ((err = pthread_atfork(prepare, parent, child)) != 0)

        err_exit(err, "can't install fork handlers");

    err = pthread_create(&tid, NULL, thr_fn, 0);

    if (err != 0)

        err_exit(err, "can't create thread");

    sleep(2);

    printf("parent about to fork...\n");

    if ((pid = fork()) < 0)

        err_quit("fork failed");

    else if (pid == 0) /* child */

        printf("child returned from fork\n");

    else        /* parent */

        printf("parent returned from fork\n");

#endif

    exit(0);

}

 

相关内容

    暂无相关文章