关于多线程安全和Socket堵塞

ArLi2003 2003-06-12 07:21:20
我只一个用户名,所以没有可用分转让之类的东东,没分了,所以本贴只有10分,原谅原谅

不少人在多线程上误解挺深的,我举个例子总结一下吧,算上版主上任第一篇谢贴:

class a:
lock (a){
//code
lock(b){
//code
}
}

class b:

lock (b){
//code
lock(a){
//code
}
}

假若,上面二个线程任意一个出现中止或挂起,将导致二个线程都死锁,永久进入睡眠状态。因为他们都在等待对方解锁。

这是一个比较容易犯的错误,这也是为什么thread.abort 要抛出异常的原因,目的就是让你知道线程异常中止,要你自己注意是否有要善后的处理。不少的贴子我都有警告过,必须要设置一个公用变量数组(推荐使用sortlist 之类的二维表),在各线程的while 内部去判断是否线程应该中止!


有些朋友提到了碰到了socket 堵塞式多线程怎么办?其实不然,那其实是你的编程误区,socket 的AcceptSocket 应该这样写(取自我过去写的sock 聊天程序):

while (cls_Const.ListenStartMode) {
if (!listener.Pending()) {
Thread.Sleep(cls_Const.ListenThreadSleep);
}
else if (!cls_Const.ServiceStartMode) {
Socket sockServer = listener.AcceptSocket();
...
}

相信cls_Const.ListenStartMode 你应该知道是什么用吧,就是控制线程是否继续运行的变量
而 cls_Const.ListenThreadSleep 是负责睡眠时间也就是socket 接受请求的间隔,目的只是为了保证CPU 在while 体内 不会跑到100%

最后要补充的是要注意定义:

sockServer.SetSocketOption(
SocketOptionLevel.Socket,
SocketOptionName.ReceiveTimeout,
cls_Const.revSockTimeOut
);

sockServer.SetSocketOption(
SocketOptionLevel.Socket,
SocketOptionName.SendTimeout,
cls_Const.sendSockTimeOut
);

里面的timeout 我想应该是知道什么意思吧,就是超时的毫秒
...全文
171 11 打赏 收藏 转发到动态 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
好运 2003-09-28
  • 打赏
  • 举报
回复
mark
RnfShadow 2003-08-18
  • 打赏
  • 举报
回复
gz
pipibug 2003-08-02
  • 打赏
  • 举报
回复
收藏
甴曱 2003-06-13
  • 打赏
  • 举报
回复
关注,学习
YJ123 2003-06-13
  • 打赏
  • 举报
回复
谢谢!!!学习ing!!!
qimini 2003-06-13
  • 打赏
  • 举报
回复
up
ArLi2003 2003-06-12
  • 打赏
  • 举报
回复
是啊是啊,所以我一开始也不敢放出来,其实重要的是:

if (!listener.Pending()) {

用处是检测当前socket 请求队列中有没有等待的,如果没有就睡觉
IceboundRock 2003-06-12
  • 打赏
  • 举报
回复
兄台的代码写的……怎么没有一行注释啊……
cmsoft 2003-06-12
  • 打赏
  • 举报
回复
study~~
ArLi2003 2003-06-12
  • 打赏
  • 举报
回复
我的其中一个类,写的比较早,算法上不够先进别怪我:

using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Text;

namespace ArLi.xChat.Server
{
public class cls_Listen
{
private fm_Server fm_Server;
public TcpListener listener = new TcpListener(cls_Const.sockPort);

public cls_Listen(fm_Server Obj)
{
fm_Server = Obj;
fm_Server.stBar_myIP.Text = Dns.GetHostByName(Dns.GetHostName()).AddressList[0].ToString();
}

private void endSock(Socket sockServer){
sockServer.Shutdown(SocketShutdown.Both);
sockServer.Close();
sockServer = null;
}

private string getUserName(Socket sockServer){
try{
byte[] recvBytes = new byte[cls_Const.sockBuffer];
int getByteLen = 0;
if (sockServer.Connected) {
getByteLen = sockServer.Receive(recvBytes,recvBytes.Length,0);
}
byte[] byteBody = new byte[getByteLen];
Array.Copy(recvBytes,0,byteBody,0,getByteLen);

string myStr = Encoding.Default.GetString(byteBody);

if (myStr.Length >4 && myStr.Substring(0,3) == "un@"){
myStr = myStr.Substring(3,myStr.Length -3);
myStr = myStr.ToLower().Trim();

if (myStr.Length < 3) {
byteBody = Encoding.Default.GetBytes("Sorry@name too short, try other name!!");
sockServer.Send(byteBody,byteBody.Length,0);
this.endSock(sockServer);
return null;
}
else if (myStr.Length > 20){
byteBody = Encoding.Default.GetBytes("Sorry@name max length 20 char, try other name!!");
sockServer.Send(byteBody,byteBody.Length,0);
this.endSock(sockServer);
return null;
}
else if (myStr.IndexOf("@")>=0) {
byteBody = Encoding.Default.GetBytes("Sorry@name can't use @ , remove @ try again!!");
sockServer.Send(byteBody,byteBody.Length,0);
this.endSock(sockServer);
return null;
}
else if (fm_Server.lstBox_UserList.Items.Contains(myStr)){
byteBody = Encoding.Default.GetBytes("Sorry@name:" + myStr + " exist in server, try other name!!");
sockServer.Send(byteBody,byteBody.Length,0);
this.endSock(sockServer);
return null;
}
else{
return myStr;
}
}
else{
return null;
}
}catch{
return null;
}
}

public void goListen(){

listener.Start();
fm_Server.AddLog("Thread Start .. wait service start ..",null);

while (cls_Const.ListenStartMode) {

if (fm_Server.chk_StartServer.Checked && cls_Const.ThreadCountNow > cls_Const.ThreadMax) {
fm_Server.AddLog("Thread Max .. Stop Service ..",null);
fm_Server.chk_StartServer.Checked = false;
}

if (!listener.Pending()) {
Thread.Sleep(cls_Const.ListenThreadSleep);
}
else if (!cls_Const.ServiceStartMode) {
Socket sockServer = listener.AcceptSocket();
byte[] strTmp = Encoding.Default.GetBytes(cls_Const.ServiceStopModeMessage);
sockServer.Send(strTmp,strTmp.Length,0);
sockServer.Shutdown(SocketShutdown.Both);
sockServer.Close();
sockServer = null;
}
else{
Socket sockServer = listener.AcceptSocket();

sockServer.SetSocketOption(
SocketOptionLevel.Socket,
SocketOptionName.ReceiveTimeout,
cls_Const.revSockTimeOut
);

sockServer.SetSocketOption(
SocketOptionLevel.Socket,
SocketOptionName.SendTimeout,
cls_Const.sendSockTimeOut
);

sockServer.Send(Encoding.Default.GetBytes(cls_Const.GlobalWelcome));

string newUserName = getUserName(sockServer);

if (newUserName == null){
if (sockServer != null && sockServer.Connected) {
byte[] strTmp = Encoding.Default.GetBytes("must input username! format of: un@myNiceName");
sockServer.Send(strTmp,strTmp.Length,0);
sockServer.Shutdown(SocketShutdown.Both);
sockServer.Close();
sockServer = null;
}
}
else{

object[] ObjTmp = new object[cls_Const.ThreadProFormatUpper];
ObjTmp[(int)cls_Const.ThreadProFormat.Name] = newUserName;
ObjTmp[(int)cls_Const.ThreadProFormat.IP] = sockServer.RemoteEndPoint;
ObjTmp[(int)cls_Const.ThreadProFormat.Time] = DateTime.Now;
ObjTmp[(int)cls_Const.ThreadProFormat.SockObj] = sockServer;

int onRevID;
if (cls_Const.arr_FreeThreadProTable.Count == 0){
lock(cls_Const.arr_ThreadProTable){

cls_Const.arr_ThreadProTable.Add(ObjTmp);
fm_Server.lstBox_UserList.Items.Add(newUserName);

onRevID = cls_Const.arr_ThreadProTable.Count -1;
}
}else{
lock(cls_Const.arr_FreeThreadProTable){
onRevID = (int)cls_Const.arr_FreeThreadProTable[0];

cls_Const.arr_ThreadProTable[onRevID] = ObjTmp;
fm_Server.lstBox_UserList.Items[onRevID] = newUserName;

cls_Const.arr_FreeThreadProTable.RemoveAt(0);
}
}

fm_Server.AddLog(ObjTmp[1].ToString() + "/" + ((DateTime)ObjTmp[2]).ToString("t") + " Join.",null);
fm_Server.newThreadRev(onRevID);
}
}
}

listener.Stop();
listener = null;
}
}
}
ArLi2003 2003-06-12
  • 打赏
  • 举报
回复
关于多线程的内容,引自:
http://expert.csdn.net/Expert/TopicView1.asp?id=1905252

socket 是补充内容,引自:
http://expert.csdn.net/Expert/TopicView1.asp?id=1906711

有不同意见的兄弟来补充一下

110,567

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧