posix-多线程

1.多线程示例

在 Linux 系统中,创建线程用的函数是 pthread_create;而线程的退出,一般用 pthread_exit 主动退出。
如果使用 exit 函数使进程结束,此时进程中的所有线程都会因进程的结束而结束。 而 pthread_join 函数用于将当前线程挂起,等待线程的结束,它是一个线程阻塞函数,调用它的函数将一直到被等待的线程结束为止,当函数返回时,被等待线程的资源被回收

#include <pthread.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//pthread_t pthread_self(void);获取线程ID
//int pthread_equal(pthread_t t1, pthread_t t2);比较两线程ID是否相等
void thread1()
{
    int i = 0;
    while (i++ < 3)
    {
        printf("this is pthread1\r\n");
        if (i == 2)
        {
            pthread_exit(0); //退出
            sleep(2);        //休眠2S
        }
    }
}

void thread2()
{
    int i = 0;
    while (i++ < 3)
    {
        printf("this is pthread2\r\n");
    }
    pthread_exit(0);
}

int main(int argc, char **argv)
{
    pthread_t id1, id2;
    int ret;

    ret = pthread_create(&id1, NULL, (void *)thread1, NULL); //创建线程,第二个参数设置属性,第四个参数可以传递参数
    if (ret != 0)
    {
        printf("create pthread1 error\r\n");
        exit(1);
    }

    ret = pthread_create(&id2, NULL, (void *)thread2, NULL);
    if (ret != 0)
    {
        printf("create pthread2 error\r\n");
        exit(1);
    }

    pthread_join(id1, NULL); //等待线程结束
    pthread_join(id2, NULL);
    return 0;
}

结果:编译的时候要带上库,否则提示函数没有定义gcc file_io.c -lpthread
理论上每次结果未必一样。
命令行查看线程,ps -T(ps -aT,单独ps只能看进程),或者去/proc/进程ID/task文件夹去看

this is pthread2
this is pthread2
this is pthread2
this is pthread1
this is pthread1
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define NUM_THREADS 4
void *BusyWork(void *t) /* 线程函数 */
{
    int i;
    long tid;
    double result = 0.0;
    tid = (long)t;
    printf("Thread %ld starting...\n", tid);
    for (i = 0; i < 1000000; i++)
    {
        result = result + sin(i) * tan(i); /* 进行数学运算 */
    }
    printf("Thread %ld done. Result = %e\n", tid, result);
    pthread_exit((void *)t); /* 带计算结果退出 */
}
int main(int argc, char *argv[])
{
    pthread_t thread[NUM_THREADS];
    int rc;
    long t;
    void *status;
    for (t = 0; t < NUM_THREADS; t++)
    {
        printf("Main: creating thread %ld\n", t);
        rc = pthread_create(&thread[t], NULL, BusyWork, (void *)t); /* 创建线程 */
        if (rc)
        {
            printf("ERROR; return code from pthread_create() is %d\n", rc);
            exit(-1);
        }
    }
    for (t = 0; t < NUM_THREADS; t++)
    {
        rc = pthread_join(thread[t], &status); /*等待线程终止,并获取返回值,非分离线程释放资源必须调用此函数或者等待进程退出(分离线程退出会自动释放资源)*/
        if (rc)
        {
            printf("ERROR; return code from pthread_join() is %d\n", rc);
            exit(-1);
        }
        printf("Main: completed join with thread %ld having a status of %ld\n", t, (long)status);
    }
    printf("Main: program completed. Exiting.\n");
    pthread_exit(NULL);
}

2.线程属性

pthread_create 函数的第二个参数,就是线程的属性, NULL 表示采用默认的属性。 线程的多项属性都是可以修改的。这些属性主要包括绑定属性、分离属性、堆栈地址、堆栈大小、优先级。其中系统默认的属性为非绑定、非分离、缺省 1M 大小的堆栈,与父进程同样级别的优先级。咱们重点来讲讲如何对这些属性进行设置,往往这些设置有固定的步骤。 通常,首先调用 pthread_attr_init 函数进行初始化,然后调用相应的属性设置函数。如果要设置绑定属性那么使用 pthread_attr_setscope,如果要设置分离属性则使 用 pthread_attr_setdetachstate , 设 置 线 程 优 先 级 则 使 用pthread_attr_getscheparam 和 pthread_attr_setchedparam。完成这些属性的设置后,就可以调用 pthread_create 函数来创建线程了

pthread_t id1, id2;
int ret;

pthread_attr_t attr;
pthread_attr_init(&attr);                                    //初始化
pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);          //设置绑定属性
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); //设置分离属性
ret = pthread_create(&id1, &attr, (void *)thread1, NULL);    //传入该参数
if (ret != 0)
{
    printf("create pthread1 error\r\n");
    exit(1);
}

3.posix互斥锁

互斥锁的操作主要包括以下几个步骤:
1. 互斥锁初始化: pthread_mutex_init
2. 互斥锁上锁: pthread_mutex_lock, pthread_mutex_trylock(非阻塞)
3. 互斥锁解锁: pthread_mutex_unlock
4. 消除互斥锁: pthread_mutex_destroy
其中,互斥锁可以分为快速互斥锁、递归互斥锁和检错互斥锁。这三种锁的区别主要在于其他未占有互斥锁的现场在希望得到互斥锁时,是否需要阻塞等待。快速锁是指调用线程会阻塞直到拥有互斥锁的线程解锁为止。递归互斥锁能够成功返回并且增加调用线程在互斥上加锁的次数(简单说就是同一个线程可以多次去获得锁,信号量就不行),而检错互斥锁则为快速互斥锁的非阻塞版本,它会立刻返回一个错误信息

#include <pthread.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
//静态初始化
//pthread_mutex_t fastmutex = PTHREAD_MUTEX_INITIALIZER;默认是快速互斥锁
//pthread_mutex_t recmutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;递归互斥锁
//pthread_mutex_t errchkmutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;检错互斥锁

//动态初始化int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr);
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

int lock_var;
timer_t end_time;

void thread1(void)
{
    int i = 0;
    while (time(NULL) < end_time)
    {
        if (pthread_mutex_lock(&mutex) != 0)
        {
            perror("pthread_mutex_lock");
        }
        else
        {
            printf("pthread1: pthread1 lock the variable\r\n");
            for (i = 0; i < 2; i++)
            {
                sleep(1);
                lock_var++;
            }
        }

        if (pthread_mutex_unlock(&mutex) != 0)
        {
            perror("pthread_mutex_unlock");
        }
        else
        {
            printf("pthread1: pthread1 unlock the variable\r\n");
            sleep(1);
        }
    }
}

void thread2(void)
{
    int ret;
    while (time(NULL) < end_time)
    {
        ret = pthread_mutex_trylock(&mutex);
        if (ret == EBUSY)
        {
            printf("pthread2:the variable is lock by pthread1\r\n");
        }
        else
        {
            if (ret != 0)
            {
                perror("pthread_mutex_trylock");
                exit(1);
            }
            else
            {
                printf("pthread2:pthread2 got lock. The variableis %d\n", lock_var);
            }

            if (pthread_mutex_unlock(&mutex) != 0)
            {
                perror("pthread_mutex_unlock");
            }
            else
            {
                printf("pthread2: pthread2 unlock the variable\r\n");
            }
        }
        sleep(3);
    }
}

int main(int argc, char **argv)
{
    pthread_t id1, id2;
    int ret;
    end_time = time(NULL) + 10;

    pthread_mutex_init(&mutex, NULL);
    ret = pthread_create(&id1, NULL, (void *)thread1, NULL);
    if (ret != 0)
    {
        printf("create pthread1 error\r\n");
        exit(1);
    }

    ret = pthread_create(&id2, NULL, (void *)thread2, NULL);
    if (ret != 0)
    {
        printf("create pthread2 error\r\n");
        exit(1);
    }

    pthread_join(id1, NULL);
    pthread_join(id2, NULL);
    return 0;
}

结果如下

`pthread2:pthread2 got lock. The variableis 0
pthread2: pthread2 unlock the variable
pthread1: pthread1 lock the variable
pthread1: pthread1 unlock the variable
pthread2:pthread2 got lock. The variableis 2
pthread2: pthread2 unlock the variable
pthread1: pthread1 lock the variable
pthread1: pthread1 unlock the variable
pthread2:pthread2 got lock. The variableis 4
pthread2: pthread2 unlock the variable
pthread1: pthread1 lock the variable
pthread1: pthread1 unlock the variable
pthread2:pthread2 got lock. The variableis 6
pthread2: pthread2 unlock the variable
pthread1: pthread1 lock the variable
pthread1: pthread1 unlock the variable

4.条件变量

主要用于线程间同步,不满足条件时线程休眠,满足条件才执行,但也不是100%同步,signal 与 wait 调用之间有间隙存在

pthread_cond_t cond = PTHREAD_COND_INITIALIZER;//静态init
int pthread_cond_init(pthread_cond_t *restrict cond,
const pthread_condattr_t *restrict attr)//动态init
int pthread_cond_destroy(pthread_cond_t *cond);//销毁
等待
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
int pthread_cond_timedwait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime);
通知
int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_signal(pthread_cond_t *cond);

5.posix信号量

信号量其实就是一个非负的整数计数器,是操作系统中所用的 PV 原语,它主要应用于进程或线程间的同步与互斥。其工作原理也很简单, PV 原语就是对整数计数器信号量 sem 进行操作,一次 P 操作使 sem 减一,而一次 V 操作使 sem 加一。 当信号量 sem 的值大于等于零时,该线程具有访问公共资源的权限;相反,当信号量 sem 的值小于零时,该线程就阻塞直到信号量 sem 的值大于等于 0 为止
在这里插入图片描述

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <semaphore.h>

/* 定义一个信号量 */
sem_t sem;
/* 待观察计数变量 */
int lock_var;	
timer_t end_time;

/* 线程一 */
void thread1(void)
{
	int i = 0;
	while(time(NULL) < end_time)
	{
		/* P操作,使得sem减一 */
		sem_wait(&sem);
		for(i =0;i < 2;i++)
		{
			sleep(1);
			lock_var++;
			printf("lock_var = %d\n",lock_var);
		}
		printf("pthread1:lock_var = %d\n",lock_var);
		/* V操作,使得sem加一 */
		sem_post(&sem);
		sleep(1);	
	}
}
/* 线程二 */
void thread2(void)
{
	int ret;
	while(time(NULL) < end_time)
	{
		/* P操作,使得sem减一 */
		sem_wait(&sem);
		printf("pthread2:pthread2 got lock;lock_var = %d\n",lock_var);
		/* V操作,使得sem加一 */
		sem_post(&sem);
		sleep(3);	
	}
}
int main()
{
	pthread_t id1,id2;
	int ret;
	end_time = time(NULL) + 10;
	
	/* 初始化信号量为1 */
	ret = sem_init(&sem,0,1);
	if(ret != 0)
	{
		printf("sem_init error\n");
		exit(1);
	}
	/* 分别创建线程1、2 */
	ret = pthread_create(&id1,NULL,(void *)thread1,NULL);
	if(ret != 0)
	{
		printf("Create pthread1 error\n");
		exit(1);
	}
	ret = pthread_create(&id2,NULL,(void *)thread2,NULL);
	if(ret != 0)
	{
		printf("Create pthread2 error\n");
		exit(1);
	}
	/* 等待线程结束 */
	pthread_join(id1,NULL);
	pthread_join(id2,NULL);
	return 0;
}

6.线程数据

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
POSIX多线程编程是一种基于UNIX操作系统的多线程编程模型,也是一种符合POSIX线程标准的编程方式。POSIX多线程编程可以帮助开发者更好地利用系统资源,并提高程序的性能和可扩展性。 POSIX多线程编程涉及的主要内容包括线程的创建、同步和调度等。通过使用线程库提供的函数和数据结构,开发者可以方便地创建和管理多个线程。线程可以共享进程的资源,包括内存、文件描述符等,这样可以避免进程间的数据传输和同步开销,提高程序的效率。 在POSIX多线程编程中,开发者可以使用同步机制来确保线程之间的正确协同工作。例如,互斥锁可以用来保护共享资源的访问,条件变量可以用来进行线程间的通信和等待。同时,开发者还可以使用信号量来进行线程间的同步和互斥操作。这些同步机制可以帮助开发者实现良好的线程互动,避免数据竞争和死锁等问题。 此外,POSIX多线程编程还提供了一些线程调度的接口,开发者可以通过调整线程的优先级和睡眠时间等参数来控制线程的执行顺序和时间片分配。这样可以更好地满足不同线程对系统资源的需求,提高程序的相应能力和性能。 综上所述,POSIX多线程编程是一种强大且灵活的编程模型,它能帮助开发者充分发挥多核处理器的计算能力,优化程序的并发性能。通过合理使用线程的创建、同步和调度等技术,开发者可以编写出更高效、更可靠的多线程应用程序。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值