Linux多线程相关的函数

1、多线程

包含头文件

#include <pthread.h>

        编译的时候需要指定库文件   -lpthread

        除了信号量,其他的头文件都是这个

查看线程id:返回值为pthread_t类型的线程id,Linux中实际上是unsigned long类型

pthread_t pthread_self(void);	// 返回当前线程的线程ID

创建线程

#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                   void *(*start_routine) (void *), void *arg);
// Compile and link with -pthread, 线程库的名字叫pthread, 全名: libpthread.so libptread.a
  • 参数:

                thread: 传出参数,是pthread_t类型,线程创建成功,会将线程 ID 写入到这个指针指向

                的内存中

                attr: 线程的属性,一般情况下使用默认属性即可,写 NULL

                start_routine: 函数指针,创建出的子线程的处理动作,也就是该函数在子线程执行,

                一般为线程执行函数的函数名即可

                arg: 作为实参传递到 start_routine 指针指向的函数内部,多个参数时创建结构体,传入

                结构体指针

  • 返回值:线程创建成功返回 0,创建失败返回对应的错误号

线程退出:调用该函数当前线程就马上退出了,并且不会影响到其他线程的正常运行

void pthread_exit(void *retval);
  • 参数:线程退出的时候携带的数据,当前子线程的主线程会得到该数据。如果不需要使用,指定为 NULL

线程回收:这个函数是一个阻塞函数,阻塞当前线程,等到要回收的线程执行完毕,回收资源

int pthread_join(pthread_t thread, void **retval);
  • 参数:

                    thread: 要被回收的子线程的线程 ID

                    retval: 二级指针,指向一级指针的地址,是一个传出参数,这个地址中存储了

                    pthread_exit () 传递出的数据,如果不需要这个参数,可以指定为 NULL

  • 返回值:线程回收成功返回 0,回收失败返回错误号。

线程分离:子线程与主线程分离,执行完毕后由操作系统回收资源

int pthread_detach(pthread_t thread);

线程取消:在线程A中杀死线程B,A调用后,B进行了一次系统调用才会被杀死,否则B一直运行

int pthread_cancel(pthread_t thread);
  • 参数:要杀死的线程的线程 ID
  • 返回值:函数调用成功返回 0,调用失败返回非 0 错误号。

线程比较:也可以直接用=,因为pthread_t本质是unsigned long类型

int pthread_equal(pthread_t t1, pthread_t t2);
  • 参数:t1 和 t2 是要比较的线程的线程 ID
  • 返回值:如果两个线程 ID 相等返回非 0 值,如果不相等返回 0

2、互斥锁

创建互斥锁:一个临界资源对应一把互斥锁,创建为全局变量,因为需要被多个线程函数访问

pthread_mutex_t  mutex;

初始化互斥锁:在主线程中初始化

// 初始化互斥锁
// restrict: 是一个关键字, 用来修饰指针, 只有这个关键字修饰的指针可以访问指向的内存地址, 其他指针是不行的
int pthread_mutex_init(pthread_mutex_t *restrict mutex,
           const pthread_mutexattr_t *restrict attr);
  • 参数:

            mutex: 互斥锁变量的地址
            attr: 互斥锁的属性,一般使用默认属性即可,这个参数指定为 NULL

  • 返回值

            成功返回0,失败返回相应的错误号码

上锁

int pthread_mutex_lock(pthread_mutex_t *mutex);

尝试上锁

int pthread_mutex_trylock(pthread_mutex_t *mutex);

解锁

int pthread_mutex_unlock(pthread_mutex_t *mutex);

销毁互斥锁:一般在主线程结束的时候销毁互斥锁

// 释放互斥锁资源            
int pthread_mutex_destroy(pthread_mutex_t *mutex);

3、读写锁

读写锁是互斥锁的升级版,在做读操作的时候可以提高程序的执行效率,如果所有的线程都是做读操作, 那么读是并行的,但是使用互斥锁,读操作也是串行的。

创建读写锁

#include <pthread.h>
pthread_rwlock_t rwlock;

初始化读写锁

int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,
           const pthread_rwlockattr_t *restrict attr);

读锁

// 在程序中对读写锁加读锁, 锁定的是读操作
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);

// 这个函数可以有效的避免死锁
// 如果加读锁失败, 不会阻塞当前线程, 直接返回错误号
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);

写锁

// 在程序中对读写锁加写锁, 锁定的是写操作
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);

// 这个函数可以有效的避免死锁
// 如果加写锁失败, 不会阻塞当前线程, 直接返回错误号
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);

解锁

// 解锁, 不管锁定了读还是写都可用解锁
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);

销毁读写锁

// 释放读写锁占用的系统资源
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);

4、条件变量

严格意义上来说,条件变量的主要作用不是处理线程同步,而是进行线程的阻塞。如果在多线程程序中只使用条件变量无法实现线程的同步,必须要配合互斥锁来使用。虽然条件变量和互斥锁都能阻塞线程,但是二者是有区别的:

  1. 如果一个线程抢到互斥锁并加锁成功,其他线程都会被阻塞,无法访问临界资源
  2. 条件变量是在满足一定的条件下阻塞当前线程,如果条件不满足了,所有线程都可以进入临界区访问临界资源,这种情况下还是会导致数据混乱。

因此,条件变量要和互斥锁配合使用,典型应用为生产者消费者模型。

创建条件变量

#include <pthread.h>
pthread_cond_t cond;

初始化条件变量

// 初始化
int pthread_cond_init(pthread_cond_t *restrict cond,
      const pthread_condattr_t *restrict attr);
  • 参数:

                    cond: 条件变量的地址

                    attr: 条件变量属性,一般使用默认属性,指定为 NULL

线程阻塞函数

// 线程阻塞函数, 哪个线程调用这个函数, 哪个线程就会被阻塞
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);

// 表示的时间是从1971.1.1到某个时间点的时间, 总长度使用秒/纳秒表示
struct timespec {
	time_t tv_sec;      /* Seconds */
	long   tv_nsec;     /* Nanoseconds [0 .. 999999999] */
};
struct timespec tmsp;
tmsp.tv_nsec = 0;
tmsp.tv_sec = time(NULL) + 100;	// 线程阻塞100s

// 将线程阻塞一定的时间长度, 时间到达之后, 线程就解除阻塞了
int pthread_cond_timedwait(pthread_cond_t *restrict cond,
           pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime);

  • 满足一定条件时,调用此函数阻塞线程,当线程被阻塞如果线程对互斥锁mutex上锁了,函数内部会把锁打开
  • 当被这个函数阻塞的线程被唤醒函数唤醒的时候,如果是所有线程都被唤醒,这些线程会抢这把互斥锁,抢到的线程就会对互斥锁进行上锁,然后进入临界区

唤醒阻塞的线程

// 唤醒阻塞在条件变量上的线程, 至少有一个被解除阻塞
int pthread_cond_signal(pthread_cond_t *cond);
// 唤醒阻塞在条件变量上的线程, 被阻塞的线程全部解除阻塞
int pthread_cond_broadcast(pthread_cond_t *cond);

销毁条件变量

// 销毁释放资源        
int pthread_cond_destroy(pthread_cond_t *cond);

5、信号量

头文件为 semaphore.h

互斥锁和信号量实现生产者消费者模型

创建信号量

#include <semaphore.h>
sem_t sem;

初始化信号量

// 初始化信号量/信号灯
int sem_init(sem_t *sem, int pshared, unsigned int value);
  • 参数:

            sem:信号量变量地址
            pshared:      0:线程同步         非 0:进程同步
            value:初始化当前信号量拥有的资源数(>=0),如果资源数为 0,线程就会被阻塞了。

消耗信号量

// 函数被调用sem中的资源就会被消耗1个, 资源数-1
int sem_wait(sem_t *sem);

//不会阻塞
int sem_trywait(sem_t *sem);

//阻塞一定时长,时间结构见pthread_cond_timedwait
int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);

调用此函数时,如果信号量为0,就阻塞(或者不阻塞)当前线程,当信号量大于0,这个线程被自动唤醒。

增加信号量

// 调用该函数给sem中的资源数+1
int sem_post(sem_t *sem);

如果有线程被这个信号量阻塞了,调用这个函数后该线程被自动唤醒

查看信号量的值

// sval是一个传出参数
int sem_getvalue(sem_t *sem, int *sval);

信号量的值通过sval返回,而不是函数返回值

销毁信号量

int sem_destroy(sem_t *sem);

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值