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)设置线程的分离状态

扫描二维码关注公众号,回复: 1349950 查看本文章
#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

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);
}

 9.线程和IO

pread pwrite在多线程环境中非常有帮助

猜你喜欢

转载自brxonline.iteye.com/blog/1134063