线程 3.27

•在一个程序里的多个执行路线就叫做线程(thread)。更准确的定义是:线程是“一个进程内部的控制序列”

•一切进程至少都有一个执行线程

•进程是资源分配的基本单位,线程是cpu调度的基本单位

CPU任务调度逻辑

以线程为单位,随机轮片(顺序随机,时间随机 ,次数随机)(CPU-公共厕所,进程-使用者)

•在进程里面创建一个新线程的时候,新的执行线程会拥有自己的堆栈(因此也就有自己的局部变量),但要与它的创建者共享全局变量、文件描述符、信号处理器和当前的子目录状态

优点:

•创建一个新线程的代价要比创建一个新进程小得多

•与进程之间的切换相比,线程之间的切换需要操作系统做的工作至少在理论上要少很多

•线程占用的资源要比进程少很多

缺点:

•编写多线程需要更全面更深入的考虑,在一个多线程程序里,因时间分配上的细微偏差或者因共享了不该共享的变量而造成不良影响的可能性是很大的

•调试一个多线程程序也比调试一个单线程程序困难得多

任何一个子线程终止一般不会影响其他线程,除非子线程执行了exit()系统调用。任何一个子线程执行exit(),全部线程同时灭亡。

在这里插入图片描述

pthread_create()

功能:创建一个新的线程

返回:成功返回0,失败返回一个错误

int  pthread_create(pthread_t *thread,pthread_attr_t *attr,
			void*(*start_routine)(void*),void *arg);
//thread:新线程创建成功后,保存新线程的标识符
//attr:设置线程的属性,一般不需要什么特殊的属性,直接传NULL即可,将采用默认的属性配置
//start_routine: 是个函数地址,线程启动后要执行的函数
//arg:传给线程启动函数的参数 

pthread_t 线程标识符

•像每个进程有一个进程ID一样,每个线程也有一个线程ID

•进程ID在整个系统中是唯一的,但线程不同,线程ID只在它所属的进程环境中有效

•线程ID用pthread_t数据类型来表示,实现的时候可以用一个结构来代表pthread_t数据类型,所以可以移植的操>作系统不能把它作为整数处理

pthread_join()

功能:pthread_join相当于进程用来等待子进程的wait函数

返回:成功时返回“0”,失败时返回一个错误代码

int pthread_join(pthread_t th, void **thread_return);
//th: 指定了将要等待的线程标识符
//thread_return: 它指向另外一个指针,而后者指向线程的返回值

一个线程执行结束的返回值只能由一个 pthread_join() 函数获取,当有多个线程调用 pthread_join() 函数获取同>一个线程的执行结果时,哪个线程最先执行 pthread_join() 函数,执行结果就由那个线程获得,其它线程的 < >pthread_join() 函数都将执行失败

pthread_mutex_t 互斥锁

头文件:<pthread.h>

int pthread_mutex_init(pthread_mutex_t *mutex,const pthread_mutexattr_t *mutexattr);//初始锁
int pthread_mutex_lock(pthread_mutex_t *mutex);//加锁
int pthread_mutex_unlock(pthread_mutex_t *mutex);//解锁
int pthread_mutex_trylock(pthread_mutex_t *mutex);//测试加锁
int pthread_mutex_destroy(pthread_mutex_t *mutex);//释放锁

加锁和解锁之间,不能由sleep()函数:

首先,执行了sleep,就可能切换到其它进程,此时,并没有调用spin_unlock释放锁。 当另外的进程(线程)再次调用同一驱动时,需要获取相同的spin lock,由于之前并没有释放锁,于是就出现死锁了。

VS默认不支持多线程开发:破解方法:工程属性->链接器->命令行->其他选项 里添加(-pthread)

~#g++ ./main.cpp -pthread -o main

课堂案例1:

#include<iostream>
#include<pthread.h>
#include<stdio.h>
#include<unistd.h>
using namespace std;

pthread_mutex_t mutex;
int num, x, y;
void* pthread_func1(void* p)
{
	while (1)
	{
		pthread_mutex_lock(&mutex);
		num++;
		if (num % 2 == 0)
		{
			x = 0;
			y = 0;
		}
		else
		{
			x = 1;
			y = 1;
		}
		pthread_mutex_unlock(&mutex);
		sleep(1);//sleep()不能写在加锁与解锁之间
	}
}
void* pthread_func2(void* p)
{
	while (1)
	{
		pthread_mutex_lock(&mutex);
		if (x == 0)
		{
			cout << "zero" << endl;
			cout << y << endl;
		}
		else
		{
			cout << "one" << endl;
			cout << y << endl;
		}
		pthread_mutex_unlock(&mutex);
		sleep(1);
	}
}

int main()
{
	pthread_mutex_init(&mutex, NULL);
	pthread_t pthreadid1;//线程ID
	pthread_t pthreadid2;//线程ID
	//两个线程公平竞争,随机执行,代码顺序不代表执行顺序
	if (pthread_create(&pthreadid1, NULL, pthread_func1, NULL))//pthread_create()是内核函数,不需要像Qt里需要start()
	{
		perror("pthread_create1 error");
	}

	if (pthread_create(&pthreadid2, NULL, pthread_func2, NULL))
	{
		perror("pthread_create2 error");
	}

	while (1)
	{
		cout << "host thread run" << endl;
		sleep(1);
	}

	pthread_mutex_destroy(&mutex);
	return 0;
}

edition 1.0

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>
#include <map>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "protocol_S.h"
using namespace std;

typedef struct chatMsg
{
	char sendID[10];
	char recvID[10];
	char msg[100];
}CHAT;

void* pthread_server(void* p);

map<char*, int> onlineMap;

int main()
{
	//pthread_mutex_init(&mutex, NULL);
	

	struct sockaddr_in s_addr;
	int len = 0;
	int socketfd = 0;
	int acceptfd = 0;
	int client_num = 0;
	socketfd = socket(AF_INET, SOCK_STREAM, 0);//初始化网络
	if (socketfd == -1)
	{
		perror("socket error");
	}
	else
	{
		s_addr.sin_family = AF_INET;//ipv4
		s_addr.sin_addr.s_addr = INADDR_ANY;//Internet地址
		s_addr.sin_port = htons(10086);
		len = sizeof(s_addr);
		if (bind(socketfd, (struct sockaddr*)&s_addr, len) == -1)
		{
			perror("bind error");
		}

		sleep(1);
		if (listen(socketfd, 10) == -1)//监听,判断   请求队列中的最大连接数为10
		{
			perror("listen error");
		}
		cout << "ready OK" << endl;//网络通道准备好了  

		pthread_t pthreadid1;//线程ID
		pthread_t pthreadid2;//线程ID

		while (1)//死循环,保证服务器长时间运行
		{
			cout << "wait" << endl;
			acceptfd = accept(socketfd, NULL, NULL);//等待客户端上线,阻塞式函数,没有响应,会一直在
			//返回客户端的IP地址
			cout << "client line succuss --- acceptfd=" << acceptfd << endl;
			//网络只能从4开始,0 1 2分别表示操作系统标准输入、输出、报错;3是文件IO操作时候文件描述符号
			client_num++;
			if(client_num==1)
				int res = pthread_create(&pthreadid1, NULL, pthread_server, &acceptfd);
			else if (client_num == 2)
				int res = pthread_create(&pthreadid2, NULL, pthread_server, &acceptfd);
		}
	}
	close(socketfd);
	return 0;
}


void* pthread_server(void* p)
{
	int fd = 0;
	fd = *((int*)p);
	CHAT buf = { 0 };
	map<char*, int>::iterator it;
	char name[20] = { 0 };
	read(fd, &buf, sizeof(buf));
	strcpy(name, buf.sendID);
	onlineMap.insert(make_pair(name, fd));
	cout << "online user num:" << onlineMap.size() << endl;

	while (1)
	{
		if (onlineMap.size() > 1)
		{
			read(fd, &buf, sizeof(buf));
			int sendfd = 0;
			for (it = onlineMap.begin(); it != onlineMap.end(); it++)
			{
				cout << buf.recvID<<"   !"<< it->first << "  !" << it->second << endl;
				if (strcmp(buf.recvID, it->first) == 0)
				{
					sendfd = it->second;
					break;
				}
			}
			cout << "sendfd=" << sendfd << endl;
			write(sendfd, &buf, sizeof(buf));
			cout << "sendid=" << buf.sendID << "   recvid=" << buf.recvID << endl;
			bzero(&buf, sizeof(buf));
		}
	}
}
#include <sys/types.h> 
#include <sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include<pthread.h>
#include<iostream>
#include<stdio.h>
#include <string.h>
#include "protocol_C.h"
using namespace std;

typedef struct chatMsg
{
	char sendID[10];
	char recvID[10];
	char msg[100];
}CHAT;

void* pthread_client(void* p);

int main()
{
	pthread_t pthreadid;//线程ID
	struct sockaddr_in s_addr;
	int len = 0;
	int socketfd = 0;
	char sendID[10] = { 0 };
	CHAT buf;
	//
	socketfd = socket(AF_INET, SOCK_STREAM, 0);
	if (socketfd == -1)
	{
		perror("socket error");
	}
	else
	{
		s_addr.sin_family = AF_INET;
		s_addr.sin_addr.s_addr = inet_addr("127.0.0.1");//本机回环ip地址即虚拟机ip  192.168.136.0
		s_addr.sin_port = htons(10086);
		len = sizeof(s_addr);
		//客户端向服务器发送连接请求
		if (connect(socketfd, (struct sockaddr*)&s_addr, len) == -1)
		{
			perror("connect error");
		}
		else
		{
			cout << "connect success" << endl;
			int res=pthread_create(&pthreadid, NULL, pthread_client, &socketfd);
			int i = 0;
			cout << "what's your ID:";
			cin >> buf.sendID;
			write(socketfd, &buf, sizeof(buf));
			while (1)
			{
				bzero(&buf, sizeof(buf));
				strcpy(buf.sendID, sendID);
				cout << "recvID=";
				cin >> buf.recvID;
				cout << "message=" ;
				cin >> buf.msg;
				write(socketfd, &buf, sizeof(buf));
			}
		}
	}
	close(socketfd);
	return 0;
}

void* pthread_client_write(void* p)
{
	cout << "what's your ID:";
	cin >> buf.sendID;
	write(fd, &buf, sizeof(buf));
	while (1)
	{
		bzero(&buf, sizeof(buf));
		strcpy(buf.sendID, sendID);
		cout << "recvID=";
		cin >> buf.recvID;
		cout << "message=";
		cin >> buf.msg;
		write(socketfd, &buf, sizeof(buf));
	}
}
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐