嵌入式Linux下的多线程编程

持续更新,最后更新日期:2024/02/22

一、理清进程和线程

1、进程和线程

1.1、进程的概念

  • 进程是计算机系统中运行的一个程序的实例;
  • 每个进程都有自己独立的内存空间,包括代码、数据和系统资源;
  • 进程之间相互独立,需要通过进程间通信(IPC)机制来进行数据交换;
  • 进程是操作系统进行资源分配和调度的基本单位;

1.2、线程的概念

  • 线程是进程中的一个执行单元,一个进程可以包含多个线程;
  • 线程共享进程的内存空间,包括代码、数据和系统资源;
  • 线程之间通过共享内存直接进行数据交换,因此线程间的通信相对简单;
  • 线程是操作系统进行调度的基本单位,相比进程更轻量级;

2、多进程和多线程

2.1、CPU处理器

从处理器说起会更好理解进程和线程的概念,这里把简单把处理器分为单核处理器多核处理器

  • 单核处理器:只有一个物理核心,一次只能执行一个指令流;
  • 多核处理器:包含多个物理核心,可以同时执行多个指令流,每个核心都是一个独立的处理单元;

2.2、基于单核处理器的多进程和多线程

  • 多进程: 因为处理器是单核的缘故,本身应该并行同时处理的多进程变成了以时间片轮转的方式执行,这时候就叫伪并行或假并行;
  • 多线程: 多线程的实现方式有两种主要模型,一种是通过时间片轮转来实现,在不同线程之间切换执行;另一种是通过事件驱动模型,其中一个线程等待事件的发生,一旦发生事件,就激活相应的线程来处理;总结来说,单核处理器下的多线程也不是并行处理的;

2.3、基于多核处理器的多进程和多线程

  • 多进程: 因为处理器是多核的缘故,每个核心都可以独立执行指令,因此多个进程可以在不同的核心上同时运行,实现真正的并行性;
  • 多线程: 多核处理器下的多线程和单核处理下的多线程略有不同,在多核处理器上,操作系统有更多的选择,可以更灵活地将线程调度到不同的核心上,以实现更好的并发性能,可以采用以下两种主要的线程调度模型:
    • 时间片轮转;
    • 绑定线程到核心: 操作系统也可以选择将线程绑定到特定的核心上。这样每个线程就会一直在分配的核心上执行,而不会频繁地切换到其他核心;
  • 总结:多核处理器上的多线程处理并不一定只采用时间片轮转的方式,操作系统有能力更灵活地处理线程调度,以充分利用多核架构的优势,这种方式相对于单核系统更能发挥多核处理器的性能潜力;

二、Linux C API

1、获取线程id

  • API
/*****************************
**@brief : 获取当前进程号
**@param : none
**@return: ID (PID)
*****************************/
pid_t getpid(void)

/*****************************
**@brief : 获取当前线程号
**@param : none
**@return: ID
*****************************/
pthread_t pthread_self(void)
  • Tips
    • /
  • 示例
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>

int main(int argc, char **argv)
{
        pid_t pid;
        pthread_t tid;

        pid = getpid();
        tid = pthread_self();

        printf("pid: %u \t tid: %lu\n", pid, tid);

        return 0;
}

2、线程创建

  • API
/*****************************
**@brief : 创建一个线程
**@param : thread 线程结构体,用于保存创建出来的线程
**@param : attr 线程属性
**@param : start_routine 线程处理函数
**@param : arg 线程处理函数参数
**@return: On success, pthread_create() returns 0; on error, it returns an error number.
*****************************/
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                          void *(*start_routine) (void *), void *arg);
  • Tips
    • 新线程可能在pthread_create()返回之前就已经开始运行,甚至在返回之前就已运行完毕,当然也可能主线程运行完了新线程还没结束;
  • 示例
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>

void print_id(char *name)
{
        pid_t pid = getpid();
        pthread_t tid = pthread_self();

        printf("%s : pid = %u \t tid = %lu\n", name, pid, tid);
}

void *thread_fun(void *arg)
{
        print_id((char *)arg);
        return (void *)0;
}

int main(int argc, char **argv)
{
        pthread_t thread;
        int err;
        
		/* 	新线程可能在pthread_create()返回之前就已经开始运行,
		*	甚至在返回之前就已运行完毕,当然也可能主线程运行完了新线程还没结束
		*/
        err = pthread_create(&thread, NULL, thread_fun, "nThread");
        if(err != 0)
                printf("pthread_create err!\n");

        print_id("main");
		
        sleep(2);

        return 0;
}

3、线程退出

  • API
/*****************************
**@brief : 退出当前线程
**@param : retval 线程返回值
**@return: none
*****************************/
 void pthread_exit(void *retval);
  • Tips
    • 线程退出的三种方式:
      • return
        只结束当前线程(常规方法,可以使用)
      • pthread_exit()
        只结束当前线程(常规方法,可以使用)
      • exit()
        直接结束进程(小心使用),该进程下的其它线程也会被结束
  • 示例
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>

void *thread_fun(void *arg)
{
        int retval;
        char *str = (char *)arg;

        if(!strcmp("1", str))
        {
        		// 1、只结束当前线程(常规方法,可以使用)
                return (void *)0;
        }
        else if(!strcmp("2", str))
        {
        		// 2、只结束当前线程(常规方法,可以使用)
                pthread_exit(&retval);
        }
        else if(!strcmp("3", str))
        {
        		// 3、直接结束进程(小心使用),该进程下的其它线程也会被结束
                exit(0);
        }
}

int main(int argc, char **argv)
{
        pthread_t thread;
        int err;

        err = pthread_create(&thread, NULL, thread_fun, argv[1]);
        if(err != 0)
                printf("pthread_create err\n");

        sleep(1);
        printf("main thread\n");

        return 0;
}

4、线程连接

  • API
/*****************************
**@brief : The pthread_join() function waits for the thread specified by thread to terminate.
**@param : thread 指定要连接的线程
**@param : retval 线程返回值
**@return: On success, pthread_join() returns 0; on error, it returns an error number.
*****************************/
int pthread_join(pthread_t thread, void **retval);
  • Tips
    • 执行pthread_join()函数 的线程会阻塞,等待指定线程运行结束后继续运行;
    • 要连接的线程不能是分离线程;
    • 应用场景:
      等待线程执行完毕;
  • 示例
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>

void *thread_fun1(void *arg)
{
        printf("i am thread_fun1\n");
        return (void *)1;
}

void *thread_fun2(void *arg)
{
        printf("i am thread_fun2\n");
        pthread_detach( pthread_self() );
        return (void *)2;
}

int main(int argc, char **argv)
{
        pthread_t thread1, thread2;
        int err;
        void *rval1, *rval2;

        err = pthread_create(&thread1, NULL, thread_fun1, NULL);
        if(err != 0)
                return -1;

        err = pthread_create(&thread2, NULL, thread_fun2, NULL);
        if(err != 0)
                return -1;

        printf("i am main\n");

		//连接线程thread1,当前线程阻塞,等待thread1执行结束
        err = pthread_join(thread1, &rval1);
        if(err != 0)
                printf("pthread_join thread1 err code : %d\n", err);
        
        //连接线程thread2,当前线程阻塞,等待thread2执行结束
        //但thread2线程里执行了pthread_detach()分离线程函数,故pthread_join()会返回错误码
        err = pthread_join(thread2, &rval2);
        if(err != 0)
                printf("pthread_join thread2 err code : %d\n", err);
		
		//rval保存线程返回值
        printf("thread1 return: %d\n", (int *)rval1);
        printf("thread2 return: %d\n", (int *)rval2);

        printf("i am main\n");
        
        return 0;
}

5、线程取消

  • API
/*****************************
**@brief : 取消指定线程
**@param : thread 指定线程
**@return: On success, pthread_cancel() returns 0; on error, it returns a nonzero error number.
*****************************/
int pthread_cancel(pthread_t thread);

/*****************************
**@brief : 设置本线程对Cancel取消信号的反应,一种是响应,一种是忽略
**@param : state PTHREAD_CANCEL_ENABLE(响应取消信号)
				 PTHREAD_CANCEL_DISABLE(忽略取消信号)
**@param : oldstate 如果不为NULL则存入原来的Cancel状态以便恢复
**@return: On success, these functions return 0; on error, they return a nonzero error number.
*****************************/
int pthread_setcancelstate(int state, int *oldstate);

/*****************************
**@brief : 设置本线程取消动作的执行时机,仅在Cancel状态为Enable是有用
**@param : state PTHREAD_CANCEL_DEFERRED(延时取消,运行到下一取消点时执行取消动作)
				 PTHREAD_CANCEL_ASYNCHRONOUS(立即执行取消动作)
**@param : oldstate 如果不为NULL则存入原来的取消动作类型值
**@return: On success, these functions return 0; on error, they return a nonzero error number.
*****************************/
int pthread_setcanceltype(int type, int *oldtype);
  • Tips
    • 线程创建时默认使能响应取消信号,默认取消类型为延时取消;
    • 被取消的线程如何知道自己要被取消?延时取消类型下,当程序执行到取消点时会检查自己是否要被取消,若被取消则取消;
    • 什么是取消点?可以查看自己是否要被取消的地方称为取消点,取消操作是内部自己完成,取消点有很多,详细查看手册pthreads中的Cancellation points;
  • 示例
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>

void *thread_fun(void *arg)
{
        int err;
        //使能响应取消,当然线程被创建时就是默认使能的
        err = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
        if(err != 0)
                printf("pthread_setcancelstate err!\n");
		
		//取消动作为延时取消,当然线程被创建时就是默认延时取消
        err = pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
        if(err != 0)
                printf("pthread_setcanceltype err!\n");
		
		sleep(2);
		
		//取消点,Cancel为Enable时,执行到这句时直接退出(不会打印)
        printf("cancel point!\n");

		//Cancel为Disable时,正常返回
        return 0;
}

int main(int argc, char **argv)
{
        pthread_t thread;
        int err;
        void *val;

        err = pthread_create(&thread, NULL, thread_fun, NULL);
        if(err != 0)
        {
                printf("pthread_create err!\n");
                return -1;
        }
		
		//取消指定线程
        err = pthread_cancel(thread);
        if(err != 0)
                printf("pthread_cancel err!\n");

        err = pthread_join(thread, &val);
        if(err != 0)
                printf("pthread_join err!\n");

        printf("i am main!\n");
        printf("thread return value : %d\n", (int *)val);

        return 0;
}

6、发生信号

  • API
/*****************************
**@brief : 发送信号给指定线程
**@param : thread 指定线程
**@param : sig 信号,该参数为0时实际不发送信号,用于检测线程是否存在
**@return: On success, pthread_kill() returns 0; on error, it returns an error number, and no signal is sent.
*****************************/
int pthread_kill(pthread_t thread, int sig);
  • Tips
    • /
  • 示例
    • /

7、信号捕获

  • API
/*****************************
**@brief : 绑定信号处理函数
**@param : signum 信号
**@param : act sigaction结构体
			   struct sigaction {
               		void     	(*sa_handler)(int);	//信号集处理程序
               		void     	(*sa_sigaction)(int, siginfo_t *, void *);
               		sigset_t   	sa_mask;			//信号屏蔽字
               		int        	sa_flags;
               		void     	(*sa_restorer)(void);
           	   };
**@return: sigaction() returns 0 on success; on error, -1 is returned, and errno is set to indicate the error.
*****************************/
int sigaction(int signum, const struct sigaction *act,
                     struct sigaction *oldact);

/*****************************
**@brief : 多线程信号屏蔽
**@param : how SIG_BLOCK(向当前的信号掩码中添加set,其中set表示要阻塞的信号组)
			   SIG_UNBLOCK(向当前的信号掩码中删除set,其中set表示要取消阻塞的信号组)
			   SIG_SETMASK(将当前的信号掩码替换为set,其中set表示新的信号掩码,
			   				在多线程中,新线程的当前信号掩码会继承创造它的线程的信号掩码)
**@param : set sigset_t结构体
**@return: On success, pthread_sigmask() returns 0; on error, it returns an error number.
*****************************/
int pthread_sigmask(int how, const sigset_t *set, sigset_t *oldset);
  • Tips
    • 在一个多线程的程序中,对于同一种信号,同一时刻只会有一个线程的信号处理函数被执行,当某个线程捕获了信号并开始执行信号处理函数时,其他线程对同一信号的处理函数将会被阻塞,直到当前线程的信号处理函数执行完毕;
    • 要注意的是,如果在信号处理函数中调用了不可重入的函数(如printf),可能会导致不确定的行为,因为信号处理函数执行期间,对其他线程的阻塞可能导致一些全局状态的不一致性;
  • 示例
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>

void sig_handler(int arg)
{
        printf("sig_handler\n");
        return;
}

void *thread_fun(void *arg)
{
        struct sigaction act;
        
        memset(&act, 0, sizeof(act));
        sigaddset(&act.sa_mask, SIGQUIT);
        act.sa_handler = sig_handler;

		//绑定信号处理函数
        sigaction(SIGQUIT, &act, NULL);
		
		//屏蔽SIGQUIT信号
		//当收到SIGQUIT信号,不会执行sig_handler()
		//注释此句,则会执行sig_handler()
        pthread_sigmask(SIG_BLOCK, &act.sa_mask, NULL);

        sleep(2);

        return (void *)0;
}

int main(int argc, char **argv)
{
        pthread_t thread;
        int err;

        err = pthread_create(&thread, NULL, thread_fun, NULL);
        if(err != 0)
        {
                printf("pthread_create err!\n");
                return -1;
        }

        sleep(1);
        
		pthread_kill(thread, SIGQUIT);
        if(err != 0)
        {
                printf("pthread_kill err!\n");
                return -1;
        }

        pthread_join(thread, NULL);
        printf("i am main\n");

        return 0;
}

8、线程清理

  • API
/*****************************
**@brief : 注册线程清理函数
**@param : routine 清理函数
**@param : arg 清理函数参数
**@return: none
*****************************/
void pthread_cleanup_push(void (*routine)(void *), void *arg);

/*****************************
**@brief : 反注册线程清理函数
**@param : execute 0(弹出清理函数,并且不执行清理函数)
				   非零值(弹出清理函数,并且执行清理函数)
**@return: none
*****************************/
void pthread_cleanup_pop(int execute);
  • Tips
    • pthread_cleanup_push() 要和 pthread_cleanup_pop() 成对调用;
    • 那注册了清理函数,清理函数什么时候会被执行?
      • 调用 pthread_exit()
      • 响应取消请求
      • 用非零参数调用pthread_cleanup_pop()
    • 线程被异常结束时不一定会执行清理函数;
  • 示例
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>

void thread_cleanup_func(void *arg)
{
        printf("i am thread_cleanup_func!\n");
}

void *thread_fun(void *arg)
{
        pthread_cleanup_push(thread_cleanup_func, NULL);

        pthread_cleanup_pop(1);

        return (void *)0;
}

int main(int argc, char **argv)
{
        pthread_t thread;
        int err;

        err = pthread_create(&thread, NULL, thread_fun, NULL);
        if(err != 0)
        {
                printf("pthread_create err!\n");
                return -1;
        }

        pthread_join(thread, NULL);
        printf("i am main\n");

        return 0;
}

9、互斥量使用

  • API
/*****************************
**@brief : 互斥量初始化
**@param : mutex 互斥量
**@param : attr 互斥量属性
**@return: On success, returns 0; on error, it returns an error number.
*****************************/
int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);

/*****************************
**@brief : 互斥量上锁,如果互斥量已经被锁住,那么会导致该线程阻塞
**@param : mutex 互斥量
**@return: On success, returns 0; on error, it returns an error number.
*****************************/
int pthread_mutex_lock(pthread_mutex_t *mutex);

/*****************************
**@brief : 互斥量上锁,如果互斥量已经被锁住,不会导致该线程阻塞
**@param : mutex 互斥量
**@return: On success, returns 0; on error, it returns an error number.
*****************************/
int pthread_mutex_trylock(pthread_mutex_t *mutex);

/*****************************
**@brief : 互斥量解锁
**@param : mutex 互斥量
**@return: On success, returns 0; on error, it returns an error number.
*****************************/
int pthread_mutex_unlock(pthread_mutex_t *mutex);

/*****************************
**@brief : 销毁互斥量
**@param : mutex 互斥量
**@return: On success, returns 0; on error, it returns an error number.
*****************************/
int pthread_mutex_destroy(pthread_mutex_t *mutex)
  • Tips
    • /
  • 示例
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>

int i = 1;
int j = 1;

pthread_mutex_t mutex;

void *thread_fun1(void *arg)
{
        while(1)
        {
                pthread_mutex_lock(&mutex);

                i++;
                j = i;

                if(i != j)
                {
                        printf("i != j, i = %d, j = %d\n", i, j);
                        return (void *)0;
                }

                pthread_mutex_unlock(&mutex);
        }

        return (void *)0;
}

void *thread_fun2(void *arg)
{
        while(1)
        {
                pthread_mutex_lock(&mutex);
                
                i++;
                j = i;

                if(i != j)
                {
                        printf("i != j, i = %d, j = %d\n", i, j);
                        return (void *)0;
                }

                pthread_mutex_unlock(&mutex);
        }

        return (void *)0;
}

int main(int argc, char **argv)
{
        pthread_t thread1, thread2;
        int err;

        err = pthread_mutex_init(&mutex, NULL);
        if(err != 0)
        {
                printf("pthread_mutex_init err!\n");
                return -1;
        }

        err = pthread_create(&thread1, NULL, thread_fun1, NULL);
        if(err != 0)
        {
                printf("pthread1_create err!\n");
                return -1;
        }

        err = pthread_create(&thread2, NULL, thread_fun2, NULL);
        if(err != 0)
        {
        		printf("pthread2_create err!\n");
                return -1;
        }

        pthread_join(thread1, NULL);
        pthread_join(thread2, NULL);
        printf("i am main\n");
		
		pthread_mutex_destroy(&mutex);
		
        return 0;
}

10、线程清理

  • API
/*****************************
**@brief : 注册线程清理函数
**@param : routine 清理函数
**@param : arg 清理函数参数
**@return: none
*****************************/
void pthread_cleanup_push(void (*routine)(void *), void *arg);

/*****************************
**@brief : 反注册线程清理函数
**@param : execute 0(弹出清理函数,并且不执行清理函数)
				   非零值(弹出清理函数,并且执行清理函数)
**@return: none
*****************************/
void pthread_cleanup_pop(int execute);
  • Tips
    • pthread_cleanup_push() 要和 pthread_cleanup_pop() 成对调用;
    • 那注册了清理函数,清理函数什么时候会被执行?
      • 调用 pthread_exit()
      • 响应取消请求
      • 用非零参数调用pthread_cleanup_pop()
    • 线程被异常结束时不一定会执行清理函数;
  • 示例
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>

void thread_cleanup_func(void *arg)
{
        printf("i am thread_cleanup_func!\n");
}

void *thread_fun(void *arg)
{
        pthread_cleanup_push(thread_cleanup_func, NULL);

        pthread_cleanup_pop(1);

        return (void *)0;
}

int main(int argc, char **argv)
{
        pthread_t thread;
        int err;

        err = pthread_create(&thread, NULL, thread_fun, NULL);
        if(err != 0)
        {
                printf("pthread_create err!\n");
                return -1;
        }

        pthread_join(thread, NULL);
        printf("i am main\n");

        return 0;
}

11、读写锁

  • API
/*****************************
**@brief : 读模式加锁
**@param : rwlock 锁
**@return: If successful,the pthread_rwlock_rdlock() function shall return zero; otherwise, an error number shall be returned to indicate the error.
*****************************/
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);

/*****************************
**@brief : 读模式加锁
**@param : rwlock 锁
**@return: The pthread_rwlock_tryrdlock() function shall return zero if the lock for reading 
			on the read-write lock object refer‐enced by rwlock is acquired. 
			Otherwise, an error number shall be returned to indicate the error.
*****************************/
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);

/*****************************
**@brief : 写模式加锁
**@param : rwlock 锁
**@return: If successful, the pthread_rwlock_wrlock() function shall return zero; otherwise, an error number shall be returned to indicate the error.
*****************************/
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);

/*****************************
**@brief : 写模式加锁
**@param : rwlock 锁
**@return: The pthread_rwlock_trywrlock() function shall return zero if the lock for writing 
			on the read-write lock object refer‐enced by rwlock is acquired. 
			Otherwise, an error number shall be returned to indicate the error.
*****************************/
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);

/*****************************
**@brief : 初始化读写锁
**@param : rwlock 锁
		   attr 读写锁属性
**@return: If successful, the pthread_rwlock_destroy() and pthread_rwlock_init() functions shall 	return zero; otherwise, an error number shall be returned to indicate the error.
*****************************/
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,
           const pthread_rwlockattr_t *restrict attr);

/*****************************
**@brief : 销毁读写锁
**@param : rwlock 锁
**@return: If successful, the pthread_rwlock_destroy() and pthread_rwlock_init() functions shall 	return zero; otherwise, an error number shall be returned to indicate the error.
*****************************/
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
  • Tips
    • 多个线程对同一个共享资源进行读加锁时,每个线程都不会相互阻塞;那竟然读资源不会造成阻塞那不加锁也行啊?答:是的,如果只考虑多线程读取的话,确实不用加读锁。但更多为了保护,防止以后有线程需要写入,所要加锁;
    • 当一个线程进行写加锁时,其他有读加锁的线程会被阻塞,同时其他写操作也会被阻塞,以确保写操作的互斥性;
  • 示例
    • /

12、条件变量

  • API
/*****************************
**@brief : 
**@param : 
**@return: 
*****************************/
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);

/*****************************
**@brief : 
**@param : 
**@return: 
*****************************/
int pthread_cond_signal(pthread_cond_t *cond);

/*****************************
**@brief : 
**@param : 
**@return: 
*****************************/
int pthread_cond_broadcast(pthread_cond_t *cond);
  • Tips
    • /
  • 示例
    • /

13、一次性初始化

  • API
/*****************************
**@brief : 
**@param : 
**@return: 
*****************************/
  • Tips
    • /
  • 示例
    • /

14、线程的分离属性

  • API
/*****************************
**@brief : 
**@param : 
**@return: 
*****************************/
  • Tips
    • /
  • 示例
    • /

15、线程的栈属性

  • API
/*****************************
**@brief : 
**@param : 
**@return: 
*****************************/
  • Tips
    • /
  • 示例
    • /

16、线程的同步属性

  • API
/*****************************
**@brief : 
**@param : 
**@return: 
*****************************/
  • Tips
    • /
  • 示例
    • /

17、线程的私有数据

  • API
/*****************************
**@brief : 创建键
**@param : key 键
		   destructor 键的析构函数,当线程使用pthread_exit()和return结束线程时,该析构函数会被调用
**@return: If successful, the pthread_key_create() function shall store the newly created key value at *key and shall return  zero. Otherwise, an error number shall be returned to indicate the error.
*****************************/
int pthread_key_create(pthread_key_t *key, void (*destructor)(void*));

/*****************************
**@brief : 将键与私有数据关联
**@param : key 键
		   value 私有数据
**@return: If successful, the pthread_setspecific() function shall return zero; otherwise, an error number shall be returned to indicate the error.
*****************************/
int pthread_setspecific(pthread_key_t key, const void *value);

/*****************************
**@brief : 获取键下关联的私有数据
**@param : key 键
**@return: The  pthread_getspecific() function shall return the thread-specific data value associated with the given key. If no thread-specific data value is associated with key, then the value NULL shall be returned.
*****************************/
void *pthread_getspecific(pthread_key_t key);

/*****************************
**@brief : 销毁键
**@param : key 键
**@return: If successful, the pthread_key_delete() function shall return zero; otherwise, an error number shall be returned to indicate the error.
*****************************/
int pthread_key_delete(pthread_key_t key);
  • Tips
    • 作用:多线程下共享同一个资源变量,值可以不一样;
  • 示例
    • /
  • 9
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值