单线程
1) 当一个线程正在写入数据时,其他线程不能写,也不能读。2) 当一个线程正在读入数据时,其他线程不能写,但能够读。
备注
我们不能让两个或两个以上的用户同时更新同一条记录,如果两个或两个以上的用户都试图同时修改同一记录,那么该记录中的信息就会被破坏。我们也不让一个用户更新数据库记录的同时,让另一用户读取记录的内容。因为读取的记录很有可能同时包含了更新和没有更新的信息,也就是说这条记录是无效的记录。
一个线程申请阅读锁的成功条件是:当前没有活动的写入线程。
一个线程申请写入锁的成功条件是:当前没有任何活动(对锁而言)的线程。
多线程
定义
每个正在系统上运行的程序都是一个进程。每个进程包含一到多个线程。进程也可能是整个程序或者是部分程序的动态执行。线程是程序中一个单一的顺序控制流程.在单个程序中同时运行多个线程完成不同的工作,称为多线程。
目的
多线程是为了同步完成多项任务,不是为了提高运行效率,而是为了提高资源使用效率来提高系统的效率。线程是在同一时间需要完成多项任务的时候实现的。例如:多线程就像火车的每一节车厢,而进程则是火车。车厢离开火车是无法跑动的,同理火车也不可能只有一节车厢。多线程的出现就是为了提高效率。
优点
1.使用线程可以把占据时间长的程序中的任务放到后台去处理2.用户界面可以更加吸引人,这样比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度
3.程序的运行速度可能加快
4.在一些等待的任务实现上如用户输入、文件读写和网络收发数据等,线程就比较有用了。
。。。。。。
缺点
1.如果有大量的线程,会影响性能,因为操作系统需要在它们之间切换。2.更多的线程需要更多的内存空间。
3.线程可能会给程序带来更多“bug”,因此要小心使用。
4.线程的中止需要考虑其对程序运行的影响。
5.通常块模型数据是在多个线程间共享的,需要防止线程死锁情况的发生。
限制
一个进程可以开启的线程受可用内存限制;具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程。
图例介绍
在一级项目中,学生考完试后我们要直接为学生的答题结果进行判分,因为分为多个题型,在判分时我们就可以使用多线程,同时对多个题型判分,如图中:
如果word判分需要2s,excel判分需要5s,ppt判分需要3s,那么判完这三个题型总共需要时间10s;
添加多线程:多个题型同时开始判分,判完总共需要时间5s。
在一级中,判分时会出现滚动条,和判分同时进行,这是用到多线程的部分,代码实现:
public partial class FrmJudge : Form
{
BackgroundWorker worker; //用于进度条 BackgroundWorker为封装好的多线程,添加引用
public static Form frmjudge;
public static frmxuanfukuang xuanfu;
private bool IsHandInSuccess = false;
public FrmJudge()
{
InitializeComponent();
worker = new BackgroundWorker();
worker.DoWork += new DoWorkEventHandler(worker_DoWork);
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
frmjudge = this;
}
public static LogEntity logInfo = new LogEntity();
#region 异步 开始事件
#region 异步 开始事件
/// <summary>
/// 异步 开始事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
DateTime beginTime = DateTime.Now;
try
{
int num = 0; //用于计算执行的操作
//杀掉所有进程
Kill();
#region 进行评分操作 2015年12月14日13:52:43 李少然
string TimeTamp = MyInfo.TimeTamp();
string studentID;
studentID = MyInfo.MystudentID();
Thread[] threadNcre = new Thread[3];
TypeSumFrationBLL typesumfration = new TypeSumFrationBLL();
logInfo.timeSpan = TimeTamp;
logInfo.studentId = studentID;
logInfo.pagerType = MyInfo.MyPaperType();
logInfo.errerInfo = string.Empty;
logInfo.excelInfo = string.Empty;
logInfo.ieInfo = string.Empty;
logInfo.pptInfo = string.Empty;
logInfo.sumErrerInfo = string.Empty;
logInfo.uploadInfo = string.Empty;
logInfo.wordInfo = string.Empty;
logInfo.winInfo = string.Empty;
logInfo.userIp = MyInfo.GetInternalIP();
//1、判分
//DateTime bt = DateTime.Now;
//threadNcre[0] = new Thread(() =>
//{
#region Word判分 2015年11月23日
try
{
WordQuestionRecordEntity student = new WordQuestionRecordEntity();
WordQuestionEntityBLL wordquestionbll = new WordQuestionEntityBLL();
WordQuestionEntity wordinfo = new WordQuestionEntity();
StudentInfoEntity studentinfo = new StudentInfoEntity();
//根据试卷类型查找题库中的题,然后对这些题根据flag进行判分
string PaperType;
PaperType = MyInfo.MyPaperType();
DataTable dt = wordquestionbll.LoadWordByPaperType(PaperType);
//得到学生答题的学生号
student.StudentID = MyInfo.MystudentID();
//word判分
JudgeWord(PaperType, student, wordquestionbll, wordinfo, dt);
//计算word总分
typesumfration.WordSumFration(studentID, TimeTamp);
num++;
}
catch (Exception em)
{
//MessageBox.Show("word问题");
logInfo.wordInfo = "word判分: " + em.Message;
}
#endregion
#region ppt判分
try
{
PptQuestionEntityBLL pptquestionbll = new PptQuestionEntityBLL();
PptQuestionEntity pptquestion = new PptQuestionEntity();
pptquestion.PaperType = MyInfo.MyPaperType();
PptQuestionRecordEntity PPTstudent = new PptQuestionRecordEntity();
PPTstudent.StudentID = FrmLogin.studentID;
PptQuestionFlag pptquestionflag = new PptQuestionFlag();
JudgePpt(MyInfo.MyPaperType().Trim().ToString(), pptquestionbll, pptquestion, PPTstudent, pptquestionflag);
//计算PPT题型总分-王荣晓-2015年11月30日
typesumfration.PPTSumFration(studentID, TimeTamp);
}
catch (Exception em)
{
//MessageBox.Show("ppt错误");
logInfo.pptInfo = "ppt错误:" + em.Message;
}
#endregion
#region Excel判分 2015年11月23日
try
{
//txtMsg.Text += "\r\nExcel开始判分......";
ExcelQuestionEntity excelinfo = new ExcelQuestionEntity();
ExcelJudgeHelper excelhelper = new ExcelJudgeHelper();
ExcelQuestionRecordEntity excelrecored = new ExcelQuestionRecordEntity();
ExcelEntityBLL Excelquestionbll = new ExcelEntityBLL();
excelhelper.SelectJudge(excelinfo);
excelrecored.StudentID = MyInfo.MystudentID();
Thread.Sleep(200);
Excelquestionbll.ReturnExcelScore(ExcelLoading.list, excelrecored);
num++;
}
catch (Exception em)
{
//MessageBox.Show("excel错误");
logInfo.excelInfo = "excel错误" + em.Message;
}
//把studentbind表中的isusebianc变成0
StudentBindPaperTypeEntity studentBin = new StudentBindPaperTypeEntity();
studentBin.TimeTamp = MyInfo.TimeTamp();
studentBin.StudentID = MyInfo.MystudentID();
studentBin.IsUse = 0;
StudentBindTypeEntityBLL studentbll = new StudentBindTypeEntityBLL();
int isuse = studentbll.UpdateStudentByIsUse(studentBin);
if (isuse == 0)
{
//DialogResult dr = MessageBox.Show(this, "交卷失败!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
//if (dr == DialogResult.OK)
//{
// return;
//}
logInfo.sumErrerInfo += "交卷失败";
}
sumFlag = true;
#endregion
IsHandInSuccess = true;
TimeSpan endTime = DateTime.Now - beginTime;
#endregion
}
catch (Exception eme)
{
IsHandInSuccess = false;
logInfo.errerInfo = "交卷失败" + eme.Message;
Control.CheckForIllegalCrossThreadCalls = false;
frmjudge.Close();
}
}
public frmWaitting(System.ComponentModel.BackgroundWorker worker,string lblInfo)
{
InitializeComponent();
worker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged);
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
label2.Text = lblInfo;
}
private void label2_Click(object sender, EventArgs e)
{
}
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.Close();
}
效果图:
在滚动条执行期间,也就是后台正在判分,直到弹出“评分完成”!
扩展模块
单线程模型
在这种线程模型中,一个进程中只能有一个线程,剩下的进程必须等待当前的线程执行完。这种模型的缺点在于系统完成一个很小的任务都必须占用很长的时间。
块线程模型(单线程多块模型STA)
这种模型里,一个程序里可能会包含多个执行的线程。在这里,每个线程被分为进程里一个单独的块。每个进程可以含有多个块,可以共享多个块中的数据。程序规定了每个块中线程的执行时间。所有的请求通过Windows消息队列进行串行化,这样保证了每个时刻只能访问一个块,因而只有一个单独的进程可以在某一个时刻得到执行。这种模型比单线程模型的好处在于,可以响应同一时刻的多个用户请求的任务而不只是单个用户请求。但它的性能还不是很好,因为它使用了串行化的线程模型,任务是一个接一个得到执行的。
多线程块模型(自由线程块模型)
多线程块模型(MTA)在每个进程里只有一个块而不是多个块。这单个块控制着多个线程而不是单个线程。这里不需要消息队列,因为所有的线程都是相同的块的一个部分,并且可以共享。这样的程序比单线程模型和STA的执行速度都要快,因为降低了系统的负载,因而可以优化来减少系统idle的时间。这些应用程序一般比较复杂,因为程序员必须提供线程同步以保证线程不会并发的请求相同的资源,因而导致竞争情况的发生。这里有必要提供一个锁机制。但是这样也许会导致系统死锁的发生。