线程的概念、创建和终止

目录

1、创建线程

2、同一个进程中的多个线程共享的资源

3、线程的终止

4、等待线程结束

5、同步

6、条件变量

7、取消

8、线程与io

9、线程与信号


1、创建线程

        系统调用的最小单位
        线程标识
        pthread_t (有可能是一个结构)

        pthread_self(3);                用来返回调用线程的 ID
        pthread_equal(3);             比较两个线程标识符  

 #include <pthread.h>

 int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                    void *(*start_routine) (void *), void *arg);

                pthread_t *thread,指向线程标识符的指针
                const pthread_attr_t *attr,设置线程属性
                void *(*start_routine) (void *), 线程运行函数的起始地址
                void *arg运行函数的参数
        功能:创建一个线程,在线程创建以后,就开始运行相关的线程函数

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

/*
 体验多线程
 线程就是独立运行的函数
 */

static void *thr_fun(void *s)
{
	for (int i = 0; i < 20; i++) {
		write(1, "!", 1);
		sleep(1);
	}
	// pthread_exit(0);
	return (void *)0;
}

int main(void)
{
	// main线程
	pthread_t tid;

	int err = pthread_create(&tid, NULL, thr_fun, NULL);
	if (err) {
		fprintf(stderr, "pthread_create():%s\n", strerror(err));
		exit(1);
	}
	

	for (int i = 0; i < 10; i++) {
		write(1, "*", 1);
		sleep(1);
	}

	// return 0;
	pthread_exit(0);
}

2、同一个进程中的多个线程共享的资源

        共享
                pid    ppid    终端    信号行为    文件表项    环境表
                用户和组    控制终端    文件屏蔽字    记录锁
                全局数据段    进程组和会话    资源限制
        不同
                tid  栈  信号屏蔽字

3、线程的终止

                从启动例程返回
                pthread_exit(3);
                被取消

4、等待线程结束

 #include <pthread.h>

 int pthread_join(pthread_t thread, void **retval);

         以阻塞的方式等待thread指定的线程结束
        retval: 用户定义的指针,用来存储被等待线程的返回值
        线程没有返回值,又或者我们不需要接收线程的返回值,可以将 retval 参数置为 NULL

5、同步

        临界区                多线程竞争的那段代码
        互斥量                保住多线程在执行临界区代码同步

常用接口

#include <pthread.h>

int pthread_mutex_init(pthread_mutex_t *restrict mutex,
    const pthread_mutexattr_t *restrict attr);

        初始化,以动态方式创建互斥锁,参数attr指定了新建互斥锁的属性。 如果参数attr为空,则使用默认的 互斥锁 属性,默认属性为快速互斥锁 

#include <pthread.h>

int pthread_mutex_lock(pthread_mutex_t *mutex);

int pthread_mutex_unlock(pthread_mutex_t *mutex);

        pthread_mutex_lock这个操作是阻塞调用的,也就是说,如果这个锁此时正在被其它线程占用, 那么 pthread_mutex_lock () 调用会进入到这个锁的排队队列中,并会进入阻塞状态, 直到拿到锁之后才会返回。
        pthread_mutex_unlock(3);该函数用来释放互斥体引用的互斥对象。释放互斥锁的方式取决于互斥锁的类型属性。

#include <pthread.h>

int pthread_mutex_destroy(pthread_mutex_t *mutex);

        用于注销一个互斥锁

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>

#define START	100
#define END		300
#define THNR	3

/*
 job > 0 已分配的数值
 job == 0 分配的数值已被任务线程取走
 job == -1 所有发放的任务已完成
 所有的线程都要存取job变量,保证同步
 */
static int job;
static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;

static int isPrimer(int n);
static void *thr_job(void *s);
int main(void)
{
	// 构建线程---》发放任务---》收尸
	pthread_t tids[THNR] = {};
	int i, err;

	for (i = 0; i < THNR; i++) {
		err = pthread_create(tids + i, NULL, thr_job, NULL);
		if (err) {
			fprintf(stderr, "pthread_create():%s\n", strerror(err));
			exit(1);
		}
	}

	for (i = START; i <= END; i++) {
		pthread_mutex_lock(&mut);
		while (job > 0) {
			// 上一次发放的任务还未被线程取走
			pthread_mutex_unlock(&mut);
			pthread_mutex_lock(&mut);
		}
		job = i;
		pthread_mutex_unlock(&mut);
	}

	// 最后一个任务被取走了。。。。job = -1 
	pthread_mutex_lock(&mut);
	while (job > 0) {
		pthread_mutex_unlock(&mut);
		pthread_mutex_lock(&mut);
	}
	job = -1;
	pthread_mutex_unlock(&mut);

	for (i = 0; i < THNR; i++)	
		pthread_join(tids[i], NULL);

	pthread_mutex_destroy(&mut);

	exit(0);
}

/*
 任务线程
 */
static void *thr_job(void *s)
{
	int num;
	// 循环取任务---》做任务(筛质数)--->终止条件job = -1
	while (1) {
		pthread_mutex_lock(&mut);
		if (job == -1) {
			pthread_mutex_unlock(&mut);
			break;
		}
		if (job == 0) {
			// 任务还未发放
			pthread_mutex_unlock(&mut);
			continue;
		}
		num = job;
		job = 0;
		pthread_mutex_unlock(&mut);

		// 以下不竞争
		if (isPrimer(num))
			printf("%d is a primer\n", num);
	
	}

	pthread_exit(0);
}

static int isPrimer(int n)
{
	for (int i = 2; i < n; i++)
		if (n % i == 0)
			return 0;
	return 1;
}

6、条件变量

        多线程在竞争资源,获取条件采用通知法

        第一步:

#include <pthread.h>

int pthread_cond_init(pthread_cond_t *restrict cond,
    const pthread_condattr_t *restrict attr);

        初始化pthread_cond_t类型的条件变量

        第二步:

#include <pthread.h>

int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_signal(pthread_cond_t *cond);

        pthread_cond_signal:发送一个信号给另外一个正在处于阻塞等待状态的线程,使其脱离阻塞状态,继续执行.如果没有线程处在阻塞等待状态,pthread_cond_signal也会成功返回。
    pthread_cond_broadcast:函数会将所有等待该条件变量的线程解锁而不是仅仅解锁一个线程

第三步:

#include <pthread.h>

int pthread_cond_wait(pthread_cond_t *restrict cond,
    pthread_mutex_t *restrict mutex);

        阻塞等待条件变量cond
        释放已掌握的互斥锁(解锁互斥量)相当于ptherad_mutex_unlock(&mutex);
        当被唤醒,pthread_cond_wait函数返回时,解除阻塞并重新申请获取互斥锁,相当于pthread_mutex_lock(&mutex);

第四步:

int pthread_cond_destroy(pthread_cond_t *cond);

        用于销毁一个条件变量

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>

#define START	100
#define END		300
#define THNR	3

/*
 job > 0 已分配的数值
 job == 0 分配的数值已被任务线程取走
 job == -1 所有发放的任务已完成
 所有的线程都要存取job变量,保证同步

 条件变量
 	pthread_cond_t
	pthread_cond_init(3)
	pthread_cond_wait(3);
	pthread_cond_signal(3) / pthread_cond_broast(3)
	pthread_cond_destroy(3);

 */
static int job;
static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

static int isPrimer(int n);
static void *thr_job(void *s);
int main(void)
{
	// 构建线程---》发放任务---》收尸
	pthread_t tids[THNR] = {};
	int i, err;

	for (i = 0; i < THNR; i++) {
		err = pthread_create(tids + i, NULL, thr_job, NULL);
		if (err) {
			fprintf(stderr, "pthread_create():%s\n", strerror(err));
			exit(1);
		}
	}

	for (i = START; i <= END; i++) {
		pthread_mutex_lock(&mut);
		// 轮询----》通知
		while (job != 0) {
			// 解锁并等待条件变化通知的到来,一旦接收到通知抢锁
			pthread_cond_wait(&cond, &mut);
		}
		job = i;
		pthread_cond_signal(&cond);
		pthread_mutex_unlock(&mut);
	}

	// 最后一个任务被取走了。。。。job = -1 
	pthread_mutex_lock(&mut);
	while (job != 0) {
		pthread_cond_wait(&cond, &mut);
	}
	job = -1;
	pthread_cond_broadcast(&cond);	
	pthread_mutex_unlock(&mut);

	for (i = 0; i < THNR; i++)	
		pthread_join(tids[i], NULL);

	pthread_mutex_destroy(&mut);
	pthread_cond_destroy(&cond);

	exit(0);
}

/*
 任务线程
 */
static void *thr_job(void *s)
{
	int num;
	// 循环取任务---》做任务(筛质数)--->终止条件job = -1
	while (1) {
		pthread_mutex_lock(&mut);
		while (job == 0) {
			// 任务还未发放
			pthread_cond_wait(&cond, &mut);
		}
		if (job == -1) {
			pthread_mutex_unlock(&mut);
			break;
		}
		num = job;
		job = 0;
		pthread_cond_broadcast(&cond);
		pthread_mutex_unlock(&mut);

		// 以下不竞争
		if (isPrimer(num))
			printf("%d is a primer\n", num);
	
	}

	pthread_exit(0);
}

static int isPrimer(int n)
{
	for (int i = 2; i < n; i++)
		if (n % i == 0)
			return 0;
	return 1;
}

7、取消

        State-->whether Type--->when
        默认state是enabled,默认的type是defferred
        pthread_cancel();
        取消点函数(man 7 pthreads)
        接受到取消请求后
                调用注册的终止处理程序
                pthread_cleanup_push(3) / pthread_cleanup_pop(3)
        线程终止

8、线程与io

         pread(3) / pwrite(3)替代read(2) / write(2)

9、线程与信号

        每一个线程都有自己的mask位图(pthread_sigmask(3))
        多线程大量与信号混用不推荐(难控制)
        多线程处理信号,专门有一个线程处理,其他线程屏蔽

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实验目的 (1)掌握Windows系统提供的线程创建撤销系统调用 (2)掌握Windows系统环境下线程创建撤销方法 2 实验准备知识 (1)线程创建 CreateThread()完成线程创建。它在调用进程的地址空间上创建一个线程,执行指定的函数,并返回新建立线程的句柄。 原型: HANDLE CreateThread(   LPSECURITY_ATTRIBUTES lpThreadAttributes,   DWORD dwStackSize,   LPTHREAD_START_ROUTINE lpStartAddress,   LPVOID lpParameter,   DWORD dwCreationFlags,   LPDWORD lpThreadId);   参数说明:   lpThreadAttributes:指向SECURITY_ATTRIBUTES型态的结构的指针。在Windows 98中忽略该参数。在Windows NT中,它被设为NULL,表示使用缺省值。   dwStackSize,线程堆栈大小,一般=0,在任何情况下,Windows根据需要动态延长堆栈的大小。   lpStartAddress,指向线程函数的指针,形式:@函数名,函数名称没有限制,但是必须以下列形式声明:   DWORD WINAPI ThreadProc (LPVOID pParam) ,格式不正确将无法调用成功。   lpParameter:向线程函数传递的参数,是一个指向结构的指针,不需传递参数时,为NULL。   dwCreationFlags :线程标志,可取值如下   CREATE_SUSPENDED: 创建一个挂起的线程   0 :创建后立即激活。   lpThreadId:保存新线程的id。   返回值:   函数成功,返回线程句柄;函数失败返回false。 (2)撤销线程 ExitThread()用于撤销当前线程 原型: VOID ExitThread( DWORD dwExitCode ); 参数说明: DwExitCode:指定线程返回码 返回值: 该函数没有返回值 用法举例: ExitThread(0); (3)挂起线程 Sleep()用于挂起当前正在执行的线程 原型: VOID Sleep( DWORD dwMilliseconds ); 参数说明: dwMilliseconds:指定挂起时间,单位为ms(毫秒)。 返回值: 该函数没有返回值。 (4)关闭句柄 函数CloseHandle()用于关闭已打开对象的句柄,其作用与释放动态申请的内存空间类似,这样可以释放系统资源,使进程安全运行。 原型: BOOL CloseHandle( HANDLE hObject ); 参数说明: hObject:已打开对象的句柄。 返回值: 成功,返回值为非0值;失败,则返回值为0.

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值