Некоторые хитрости помогут. Здесь я сначала нанесу все маркеры на белый, а затем снова нарисую сверху, используя нужный цвет.
import matplotlib
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
# make-up some data
goal_x = list(range(10))
goal_y = list(range(10))
goal_z = list(range(10))
epoch_arr = np.linspace(0,1,10)
fig = plt.figure(figsize=(8,8))
ax3D = fig.add_subplot(111, projection='3d')
ax3D.set_facecolor('xkcd:salmon')
# First plot: all markers are in white color
ax3D.scatter(goal_x, goal_y, goal_z, s=500, c='w', marker='o', alpha=1.0, zorder=10)
colormap = plt.get_cmap("binary")
norm = matplotlib.colors.Normalize(vmin=min(epoch_arr), vmax=max(epoch_arr))
#ax3D.scatter(goal_x, goal_y, goal_z, s=100, c=colormap(norm(epoch_arr.values)), marker='o')
# Second plot: use intended colormap
ax3D.scatter(goal_x, goal_y, goal_z, s=500, c='b', marker='o', zorder=11)
plt.show()
Результирующий сюжет:
Проблема в том, что вы используете Pulse / Wait в качестве сигнала. Правильный сигнал, такой как AutoResetEvent, имеет такое состояние, что он остается активированным до тех пор, пока поток не вызовет WaitOne (). Вызов Pulse без каких-либо ожидающих его потоков превратится в noop.
Это сочетается с тем фактом, что блокировка может быть взята много раз одним и тем же потоком. Поскольку вы используете асинхронное программирование, обратный вызов Accept может быть вызван тем же потоком, что и BeginAcceptTcpClient.
Позвольте мне проиллюстрировать. Я закомментировал второй сервер и изменил код на вашем сервере.
void ThreadStart()
{
if (!running)
{
listener.Start();
running = true;
lock (sync)
{
while (running)
{
try
{
Console.WriteLine("BeginAccept [{0}]",
Thread.CurrentThread.ManagedThreadId);
listener.BeginAcceptTcpClient(new AsyncCallback(Accept), listener);
Console.WriteLine("Wait [{0}]",
Thread.CurrentThread.ManagedThreadId);
Monitor.Wait(sync); // Release lock and wait for a pulse
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
}
}
}
void Accept(IAsyncResult result)
{
// Let the server continue listening
lock (sync)
{
Console.WriteLine("Pulse [{0}]",
Thread.CurrentThread.ManagedThreadId);
Monitor.Pulse(sync);
}
if (running)
{
TcpListener localListener = (TcpListener)result.AsyncState;
using (TcpClient client = localListener.EndAcceptTcpClient(result))
{
handler.Handle(client.GetStream());
}
}
}
Результат моего прогона показан ниже. Если вы запустите этот код самостоятельно, значения будут другими, но в целом они будут одинаковыми.
Press return to test...
BeginAccept [3]
Wait [3]
Press return to terminate...
Pulse [5]
BeginAccept [3]
Pulse [3]
Echo Handler: Test1
Echo Handler: Test3
Wait [3]
Как видите, вызываются два Pulse, один из отдельного потока (Pulse [5]), который пробуждает первый Wait. Затем поток 3 выполняет еще один BeginAccept, но, имея ожидающие входящие соединения, этот поток решает немедленно вызвать обратный вызов Accept. Поскольку Accept вызывается одним и тем же потоком, Lock (синхронизация) не блокируется, а сразу же Pulse [3] в пустой очереди потока.
Вызываются два обработчика, которые обрабатывают два сообщения.
Все в порядке. , и ThreadStart снова запускается и переходит в состояние ожидания на неопределенное время.
Теперь основная проблема заключается в том, что вы пытаетесь использовать монитор в качестве сигнала. Поскольку он не запоминает состояние, второй Pulse теряется.
Но для этого есть простое решение. Используйте AutoResetEvents, это правильный сигнал, и он запомнит свое состояние.
public Server(IHandler handler, int port)
{
this.handler = handler;
IPAddress address = Dns.GetHostEntry(Dns.GetHostName()).AddressList[0];
listener = new TcpListener(address, port);
running = false;
_event = new AutoResetEvent(false);
}
public void Start()
{
Thread thread = new Thread(ThreadStart);
thread.Start();
}
public void Stop()
{
listener.Stop();
running = false;
_event.Set();
}
void ThreadStart()
{
if (!running)
{
listener.Start();
running = true;
while (running)
{
try
{
listener.BeginAcceptTcpClient(new AsyncCallback(Accept), listener);
_event.WaitOne();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
}
}
void Accept(IAsyncResult result)
{
// Let the server continue listening
_event.Set();
if (running)
{
TcpListener localListener = (TcpListener) result.AsyncState;
using (TcpClient client = localListener.EndAcceptTcpClient(result))
{
handler.Handle(client.GetStream());
}
}
}