LInux C++多线程编程基础(汇总)

1. 前言

    本次来写一篇关于C++多线程的基本使用。前面有一篇是互斥锁的入门,学了两天,做一下总结。


2. 多线程

    (1) 创建

多线程的表示pthread_t:

/* Thread identifiers.  The structure of the attribute type is not
   exposed on purpose.  */
typedef unsigned long int pthread_t;

在源码中,pthread_t实际上就只是一个无符号的long int变量,用于线程的唯一标识符。

下面是pthread_create的原型:

/* Create a new thread, starting with execution of START-ROUTINE
   getting passed ARG.  Creation attributed come from ATTR.  The new
   handle is stored in *NEWTHREAD.  */
extern int pthread_create (pthread_t *__restrict __newthread,
			   const pthread_attr_t *__restrict __attr,
			   void *(*__start_routine) (void *),
			   void *__restrict __arg) __THROWNL __nonnull ((1, 3));

参数介绍:

    __newthread表示线程的唯一标识符

    __attr表示线程的属性,之后会介绍几个小方面的

    __*(*__start_rountine)(void *)这个实际上就是一个函数的指针

    __arg表示函数的参数,需要将其转化成void*指针才可以传值

线程创建之后如果不进行其他的操作,那么线程会在主线程结束的时候就结束,主线程不会等到所有线程结束后才结束,例如下面的代码:

#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t count_nonzero;
unsigned count;

void* decrement_count(void* data)
{
    pthread_mutex_lock(&mut);

    while(count == 0)
    {
        printf("1\n");
        pthread_cond_wait(&count_nonzero,&mut);
    }

    count = count -1;
    printf("Dec\n");

    pthread_mutex_unlock(&mut);
}

void* increment_count(void* data)
{
    pthread_mutex_lock(&mut);

    if(count == 0)
        pthread_cond_signal(&count_nonzero);

    count = count + 1;
    printf("inc\n");
    pthread_mutex_unlock(&mut);
}


int main()
{
    count = 0;
    pthread_t tid[2];
    pthread_create(&tid[0],NULL,decrement_count,NULL);
    pthread_create(&tid[1],NULL,increment_count,NULL);

    printf("main\n");
}

其运行结果可以为下面的一种:

第一种
1
main

第二种
inc
main

第三种
1
inc
main
...

当然后面那些需要你的线程抢到主线程的资源,否则你会发现永远是第一种情况。

第一种是什么情况呢?

很简单,主线程创建了新的线程,线程的运行顺序是没有保证的,这个时候第一个线程就先运行,但是又发现count = 0,线程就把锁释放。然后回到主线程,主线程又因为在main之后就结束了,使得这两个线程根本就没有时间执行,导致输出以这种结果。

    (2) 线程的属性

属性对象主要包括是否绑定,是否分离,堆栈地址,堆栈大小,优先级等。

分离属性(detachstate):

    分离:线程自己运行结束,则马上释放资源。

    不分离:如果加入pthread_join中,则需要等待pthread_join执行完毕之后才算结束,并且释放资源。

所对应的宏定义为:

    分离:PTHREAD_CREATE_DETACHED

    不分离:PTHREAD_CREATE_JOINABLE

设置函数为:

/* Set detach state attribute.  */
extern int pthread_attr_setdetachstate (pthread_attr_t *__attr,
					int __detachstate)
     __THROW __nonnull ((1));

注意,如果设置线程为分离的时候,线程的可能回现在pthread_create函数之前已经完成,导致返回错误的线程标识符。可以添加pthread_cond_timewait()来让线程等待一段时间,不能使用wait(),这个会使得整个进程都进入等待,并不能解决问题。


优先级属性(SCHED_PARAM):

    就是线程执行的优先级,优先级高的先执行,当然,这在并发编程中也是没有保证的。

设置函数:

/* Return in *PARAM the scheduling parameters of *ATTR.  */
extern int pthread_attr_getschedparam (const pthread_attr_t *__restrict __attr,
				       struct sched_param *__restrict __param)
     __THROW __nonnull ((1, 2));

/* Set scheduling parameters (priority, etc) in *ATTR according to PARAM.  */
extern int pthread_attr_setschedparam (pthread_attr_t *__restrict __attr,
				       const struct sched_param *__restrict
				       __param) __THROW __nonnull ((1, 2));

设置样例:

pthread_t tid[2];

pthread_attr_t attr;
sched_param param;
pthread_attr_init(&attr);
pthread_attr_getschedparam(&attr,¶m);
param.__sched_priority = 20;
pthread_attr_setschedparam(&attr,¶m);
pthread_create(&tid[0],&attr,decrement_count,NULL);

        (3) pthread_join/pthread_exit

/* Make calling thread wait for termination of the thread TH.  The
   exit status of the thread is stored in *THREAD_RETURN, if THREAD_RETURN
   is not NULL.

   This function is a cancellation point and therefore not marked with
   __THROW.  */
extern int pthread_join (pthread_t __th, void **__thread_return);

pthread_join:可以将不分离的线程连接起来,直到这个函数调用结束的时候,线程才释放资源。这样也就可以解决前面的出现那种主线程结束了,线程没有执行完成就结束的情况。当然,这个会阻塞当前线程,直到所有的线程结束为止。

/* Terminate calling thread.

   The registered cleanup handlers are called via exception handling
   so we cannot mark this function with __THROW.*/
extern void pthread_exit (void *__retval) __attribute__ ((__noreturn__));

pthread_exit退出线程。这个后面的参数是返回值,返回值可以在__thread_return中。

下面是之前的代码:

#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t count_nonzero;
unsigned count;

void* decrement_count(void* data)
{
    pthread_mutex_lock(&mut);

    while(count == 0)
    {
        printf("1\n");
        pthread_cond_wait(&count_nonzero,&mut);
    }

    count = count -1;
    printf("Dec\n");

    pthread_mutex_unlock(&mut);
    pthread_exit(NULL);
}

void* increment_count(void* data)
{
    pthread_mutex_lock(&mut);

    if(count == 0)
        pthread_cond_signal(&count_nonzero);

    count = count + 1;
    printf("inc\n");
    pthread_mutex_unlock(&mut);
    pthread_exit(NULL);
}


int main()
{
    count = 0;
    pthread_t tid[2];

    pthread_attr_t attr;
    sched_param param;
    pthread_attr_init(&attr);
    pthread_attr_getschedparam(&attr,¶m);
    param.__sched_priority = 20;
    pthread_attr_setschedparam(&attr,¶m);
    pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_JOINABLE);
    pthread_create(&tid[0],&attr,decrement_count,NULL);
    pthread_create(&tid[1],&attr,increment_count,NULL);

    pthread_join(tid[0],NULL);
    pthread_join(tid[1],NULL);

    printf("main\n");
}

运行结果为:

1
inc
Dec
main

到这里,线程的知识基本上就这些了。


3. C++11 thread类

C++11中新添加了一个线程的类,在头文件中。

使用示例:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t count_nonzero;
unsigned count;

void decrement_count()
{
    pthread_mutex_lock(&mut);

    while(count == 0)
    {
        printf("1\n");
        pthread_cond_wait(&count_nonzero,&mut);
    }

    count = count -1;
    printf("Dec\n");

    pthread_mutex_unlock(&mut);
    pthread_exit(NULL);
}

void increment_count()
{
    pthread_mutex_lock(&mut);

    if(count == 0)
        pthread_cond_signal(&count_nonzero);

    count = count + 1;
    printf("inc\n");
    pthread_mutex_unlock(&mut);
    pthread_exit(NULL);
}


int main()
{
    count = 0;
    thread t[2];
    t[0] = thread(decrement_count);
    t[1] = thread(increment_count);
    t[0].join();
    t[1].join();
}

有没有觉得函数变得简单易懂,而且很符合我们的编程习惯了= =

这个需要在执行join的时候才会运行线程,如果在主线程结束之前,没有join,会输出错误。

而且这个join是不会保证执行的顺序的,也就是主线程和join的线程的执行顺序是没有保证的,join只是保证join的线程一定能够运行到结束。


参考链接:

https://blog.csdn.net/stone_overlooking/article/details/78520945

http://www.runoob.com/cplusplus/cpp-multithreading.html

https://blog.csdn.net/chenxun_2010/article/details/49785611


你可能感兴趣的:(C++,linux,多线程编程)